3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include "mono/metadata/profiler.h"
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/utils/mono-math.h>
55 #include <mono/utils/mono-compiler.h>
56 #include <mono/utils/mono-counters.h>
57 #include <mono/utils/mono-error-internals.h>
58 #include <mono/utils/mono-logger-internals.h>
59 #include <mono/utils/mono-mmap.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-tls.h>
62 #include <mono/utils/mono-hwcap.h>
63 #include <mono/utils/dtrace.h>
64 #include <mono/utils/mono-signal-handler.h>
65 #include <mono/utils/mono-threads.h>
66 #include <mono/utils/mono-threads-coop.h>
67 #include <mono/utils/checked-build.h>
68 #include <mono/utils/mono-proclib.h>
69 #include <mono/metadata/w32handle.h>
70 #include <mono/metadata/threadpool.h>
73 #include "seq-points.h"
80 #include "jit-icalls.h"
83 #include "mini-llvm.h"
84 #include "debugger-agent.h"
87 #ifdef MONO_ARCH_LLVM_SUPPORTED
89 #include "mini-llvm-cpp.h"
94 #ifdef ENABLE_INTERPRETER
95 #include "interp/interp.h"
98 static guint32 default_opt = 0;
99 static gboolean default_opt_set = FALSE;
101 gboolean mono_compile_aot = FALSE;
102 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
103 gboolean mono_aot_only = FALSE;
104 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
105 gboolean mono_llvm_only = FALSE;
106 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NONE;
108 const char *mono_build_date;
109 gboolean mono_do_signal_chaining;
110 gboolean mono_do_crash_chaining;
111 int mini_verbose = 0;
114 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
115 * it can load AOT code compiled by LLVM.
117 gboolean mono_use_llvm = FALSE;
119 gboolean mono_use_interpreter = FALSE;
121 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
122 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
123 static mono_mutex_t jit_mutex;
125 static MonoCodeManager *global_codeman;
127 MonoDebugOptions debug_options;
129 #ifdef VALGRIND_JIT_REGISTER_MAP
130 int valgrind_register;
132 GList* mono_aot_paths;
134 static gboolean mini_enable_profiler = FALSE;
135 static char* mini_profiler_options = NULL;
137 static GSList *tramp_infos;
139 static void register_icalls (void);
141 static gboolean mini_profiler_enabled (void) { return mini_enable_profiler; }
142 static const char* mini_profiler_get_options (void) { return mini_profiler_options; }
145 mono_running_on_valgrind (void)
148 if (RUNNING_ON_VALGRIND){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register = TRUE;
164 find_tramp (gpointer key, gpointer value, gpointer user_data)
166 FindTrampUserData *ud = (FindTrampUserData*)user_data;
169 ud->method = (MonoMethod*)key;
173 G_GNUC_UNUSED static char*
174 get_method_from_ip (void *ip)
180 MonoDomain *domain = mono_domain_get ();
181 MonoDebugSourceLocation *location;
182 FindTrampUserData user_data;
185 domain = mono_get_root_domain ();
187 ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
190 user_data.method = NULL;
191 mono_domain_lock (domain);
192 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
193 mono_domain_unlock (domain);
194 if (user_data.method) {
195 char *mname = mono_method_full_name (user_data.method, TRUE);
196 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
202 } else if (ji->is_trampoline) {
203 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
207 method = jinfo_get_method (ji);
208 method_name = mono_method_full_name (method, TRUE);
209 /* FIXME: unused ? */
210 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
212 res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
214 mono_debug_free_source_location (location);
215 g_free (method_name);
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
235 return get_method_from_ip (ip);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
250 mono_print_method_from_ip (void *ip)
254 MonoDebugSourceLocation *source;
255 MonoDomain *domain = mono_domain_get ();
256 MonoDomain *target_domain = mono_domain_get ();
257 FindTrampUserData user_data;
258 MonoGenericSharingContext*gsctx;
259 const char *shared_type;
262 domain = mono_get_root_domain ();
263 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
264 if (ji && ji->is_trampoline) {
265 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
273 user_data.method = NULL;
274 mono_domain_lock (domain);
275 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
276 mono_domain_unlock (domain);
278 if (user_data.method) {
279 char *mname = mono_method_full_name (user_data.method, TRUE);
280 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
285 g_print ("No method at %p\n", ip);
289 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
290 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
292 gsctx = mono_jit_info_get_generic_sharing_context (ji);
295 if (gsctx->is_gsharedvt)
296 shared_type = "gsharedvt ";
298 shared_type = "gshared ";
301 g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
304 g_print ("%s:%d\n", source->source_file, source->row);
307 mono_debug_free_source_location (source);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
321 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller->domain_neutral && !callee->domain_neutral)
331 cmethod = jinfo_get_method (caller);
332 if ((cmethod->klass == mono_defaults.appdomain_class) &&
333 (strstr (cmethod->name, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman) {
354 /* This can happen during startup */
355 global_codeman = mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman, size);
360 ptr = mono_code_manager_reserve (global_codeman, size);
366 /* The callback shouldn't take any locks */
368 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
371 mono_code_manager_foreach (global_codeman, func, user_data);
376 * mono_create_unwind_op:
378 * Create an unwind op with the given parameters.
381 mono_create_unwind_op (int when, int tag, int reg, int val)
383 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
394 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
396 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
399 res->has_context = context != NULL;
401 memcpy (&res->context, context, sizeof (MonoGenericContext));
407 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
409 return mono_jump_info_token_new2 (mp, image, token, NULL);
413 * mono_tramp_info_create:
415 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
416 * of JI, and UNWIND_OPS.
419 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
421 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
423 info->name = g_strdup ((char*)name);
425 info->code_size = code_size;
427 info->unwind_ops = unwind_ops;
433 mono_tramp_info_free (MonoTrampInfo *info)
438 mono_free_unwind_info (info->unwind_ops);
439 if (info->owns_uw_info)
440 g_free (info->uw_info);
445 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
449 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
450 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
451 ji->d.tramp_info = info;
452 ji->is_trampoline = TRUE;
454 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
456 mono_jit_info_table_add (domain, ji);
460 * mono_tramp_info_register:
462 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
467 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
475 domain = mono_get_root_domain ();
478 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
480 copy = g_new0 (MonoTrampInfo, 1);
482 copy->code = info->code;
483 copy->code_size = info->code_size;
484 copy->name = g_strdup (info->name);
486 if (info->unwind_ops) {
487 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
488 copy->owns_uw_info = TRUE;
490 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
491 guint8 *temp = copy->uw_info;
492 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
493 memcpy (copy->uw_info, temp, copy->uw_info_len);
497 /* Trampolines from aot have the unwind ops already encoded */
498 copy->uw_info = info->uw_info;
499 copy->uw_info_len = info->uw_info_len;
502 mono_save_trampoline_xdebug_info (info);
503 mono_lldb_save_trampoline_info (info);
505 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
507 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
511 /* If no root domain has been created yet, postpone the registration. */
513 tramp_infos = g_slist_prepend (tramp_infos, copy);
515 } else if (copy->uw_info) {
516 /* Only register trampolines that have unwind infos */
517 register_trampoline_jit_info (domain, copy);
520 if (mono_jit_map_is_enabled ())
521 mono_emit_jit_tramp (info->code, info->code_size, info->name);
523 mono_tramp_info_free (info);
527 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
529 mono_tramp_info_register_internal (info, domain, FALSE);
533 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
535 mono_tramp_info_register_internal (info, domain, TRUE);
539 mono_tramp_info_cleanup (void)
543 for (l = tramp_infos; l; l = l->next) {
544 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
546 mono_tramp_info_free (info);
548 g_slist_free (tramp_infos);
551 /* Register trampolines created before the root domain was created in the jit info tables */
553 register_trampolines (MonoDomain *domain)
557 for (l = tramp_infos; l; l = l->next) {
558 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
560 register_trampoline_jit_info (domain, info);
564 G_GNUC_UNUSED static void
570 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
571 * Set a breakpoint in break_count () to break the last time <x> is done.
573 G_GNUC_UNUSED gboolean
574 mono_debug_count (void)
576 static int count = 0, int_val = 0;
577 static gboolean inited, has_value = FALSE;
582 char *value = g_getenv ("COUNT");
584 int_val = atoi (value);
594 if (count == int_val)
604 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
609 gconstpointer trampoline;
610 MonoDomain *domain = mono_get_root_domain ();
611 gboolean check_exc = TRUE;
613 if (callinfo->wrapper)
614 return callinfo->wrapper;
616 if (callinfo->trampoline)
617 return callinfo->trampoline;
619 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
620 /* This icall is used to check for exceptions, so don't check in the wrapper */
623 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
624 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
628 trampoline = mono_compile_method_checked (wrapper, &error);
629 mono_error_assert_ok (&error);
632 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
633 mono_error_assert_ok (&error);
634 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
638 if (!callinfo->trampoline) {
639 mono_register_jit_icall_wrapper (callinfo, trampoline);
640 callinfo->trampoline = trampoline;
642 mono_loader_unlock ();
644 return callinfo->trampoline;
648 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
650 return mono_icall_get_wrapper_full (callinfo, FALSE);
653 static MonoJitDynamicMethodInfo*
654 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
656 MonoJitDynamicMethodInfo *res;
658 if (domain_jit_info (domain)->dynamic_code_hash)
659 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
666 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
669 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
671 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
673 g_assert (!sig->hasthis);
674 g_assert (sig->param_count < 3);
676 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
677 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
682 * For JIT icalls implemented in C.
683 * NAME should be the same as the name of the C function whose address is FUNC.
684 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
685 * can't throw exceptions.
688 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
690 MonoMethodSignature *sig;
693 sig = mono_create_icall_signature (sigstr);
697 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
701 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
703 MonoMethodSignature *sig;
706 sig = mono_create_icall_signature (sigstr);
710 mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
714 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
716 MonoMethodSignature *sig;
719 sig = mono_create_icall_signature (sigstr);
723 mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
727 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
729 MonoMethodSignature *sig;
732 sig = mono_create_icall_signature (sigstr);
736 mono_register_jit_icall (func, name, sig, save);
742 MonoJitTlsData *jit_tls;
744 if ((jit_tls = mono_tls_get_jit_tls ()))
747 * We do not assert here because this function can be called from
748 * mini-gc.c on a thread that has not executed any managed code, yet
749 * (the thread object allocation can trigger a collection).
755 mono_get_lmf_addr (void)
757 return (MonoLMF **)mono_tls_get_lmf_addr ();
761 mono_set_lmf (MonoLMF *lmf)
763 (*mono_get_lmf_addr ()) = lmf;
767 mono_get_jit_tls (void)
769 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
773 mono_set_jit_tls (MonoJitTlsData *jit_tls)
775 MonoThreadInfo *info;
777 mono_tls_set_jit_tls (jit_tls);
779 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
780 info = mono_thread_info_current ();
782 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
786 mono_set_lmf_addr (gpointer lmf_addr)
788 MonoThreadInfo *info;
790 mono_tls_set_lmf_addr (lmf_addr);
792 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
793 info = mono_thread_info_current ();
795 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
801 * Push an MonoLMFExt frame on the LMF stack.
804 mono_push_lmf (MonoLMFExt *ext)
806 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
809 lmf_addr = mono_get_lmf_addr ();
811 mono_arch_init_lmf_ext (ext, *lmf_addr);
813 mono_set_lmf ((MonoLMF*)ext);
822 * Pop the last frame from the LMF stack.
825 mono_pop_lmf (MonoLMF *lmf)
827 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
831 * mono_jit_thread_attach:
833 * Called by Xamarin.Mac and other products. Attach thread to runtime if
834 * needed and switch to @domain.
836 * @return the original domain which needs to be restored, or NULL.
839 mono_jit_thread_attach (MonoDomain *domain)
844 g_assert (!mono_threads_is_blocking_transition_enabled ());
847 /* Happens when called from AOTed code which is only used in the root domain. */
848 domain = mono_get_root_domain ();
853 attached = mono_tls_get_jit_tls () != NULL;
856 mono_thread_attach (domain);
859 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
862 orig = mono_domain_get ();
864 mono_domain_set (domain, TRUE);
866 return orig != domain ? orig : NULL;
870 * mono_jit_set_domain:
872 * Set domain to @domain if @domain is not null
875 mono_jit_set_domain (MonoDomain *domain)
877 g_assert (!mono_threads_is_blocking_transition_enabled ());
880 mono_domain_set (domain, TRUE);
885 * \param obj exception object
886 * Abort the thread, print exception information and stack trace
889 mono_thread_abort (MonoObject *obj)
891 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
893 /* handle_remove should be eventually called for this thread, too
896 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
897 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
900 mono_invoke_unhandled_exception_hook (obj);
905 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
907 MonoJitTlsData *jit_tls;
910 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
914 jit_tls = g_new0 (MonoJitTlsData, 1);
916 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
917 jit_tls->end_of_stack = stack_start;
919 mono_set_jit_tls (jit_tls);
921 lmf = g_new0 (MonoLMF, 1);
922 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
924 jit_tls->first_lmf = lmf;
926 mono_set_lmf_addr (&jit_tls->lmf);
930 #ifdef MONO_ARCH_HAVE_TLS_INIT
931 mono_arch_tls_init ();
934 mono_setup_altstack (jit_tls);
940 free_jit_tls_data (MonoJitTlsData *jit_tls)
942 mono_arch_free_jit_tls_data (jit_tls);
943 mono_free_altstack (jit_tls);
945 g_free (jit_tls->first_lmf);
950 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
952 MonoThreadInfo *thread;
953 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
954 thread = mono_thread_info_current_unchecked ();
956 thread->jit_data = jit_tls;
958 mono_arch_cpu_init ();
961 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
964 mono_thread_abort_dummy (MonoObject *obj)
966 if (mono_thread_attach_aborted_cb)
967 mono_thread_attach_aborted_cb (obj);
969 mono_thread_abort (obj);
973 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
975 MonoThreadInfo *thread;
976 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
977 thread = mono_thread_info_current_unchecked ();
979 thread->jit_data = jit_tls;
981 mono_arch_cpu_init ();
985 mini_thread_cleanup (MonoNativeThreadId tid)
987 MonoJitTlsData *jit_tls = NULL;
988 MonoThreadInfo *info;
990 info = mono_thread_info_current_unchecked ();
992 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
993 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
994 * not a trivial thing.
996 * The current offender is mono_thread_manage which cleanup threads from the outside.
998 if (info && mono_thread_info_get_tid (info) == tid) {
999 jit_tls = (MonoJitTlsData *)info->jit_data;
1000 info->jit_data = NULL;
1002 mono_set_jit_tls (NULL);
1004 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1005 if (mono_get_lmf ()) {
1006 mono_set_lmf (NULL);
1007 mono_set_lmf_addr (NULL);
1010 info = mono_thread_info_lookup (tid);
1012 jit_tls = (MonoJitTlsData *)info->jit_data;
1013 info->jit_data = NULL;
1015 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1019 free_jit_tls_data (jit_tls);
1023 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1025 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1029 ji->data.target = target;
1035 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1037 static const char* const patch_info_str[] = {
1038 #define PATCH_INFO(a,b) "" #a,
1039 #include "patch-info.h"
1044 mono_ji_type_to_string (MonoJumpInfoType type)
1046 return patch_info_str [type];
1050 mono_print_ji (const MonoJumpInfo *ji)
1053 case MONO_PATCH_INFO_RGCTX_FETCH: {
1054 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1056 printf ("[RGCTX_FETCH ");
1057 mono_print_ji (entry->data);
1058 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1061 case MONO_PATCH_INFO_METHODCONST: {
1062 char *s = mono_method_full_name (ji->data.method, TRUE);
1063 printf ("[METHODCONST - %s]", s);
1067 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1068 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1072 printf ("[%s]", patch_info_str [ji->type]);
1080 mono_ji_type_to_string (MonoJumpInfoType type)
1086 mono_print_ji (const MonoJumpInfo *ji)
1093 * mono_patch_info_dup_mp:
1095 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1098 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1100 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1101 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1103 switch (patch_info->type) {
1104 case MONO_PATCH_INFO_RVA:
1105 case MONO_PATCH_INFO_LDSTR:
1106 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1107 case MONO_PATCH_INFO_LDTOKEN:
1108 case MONO_PATCH_INFO_DECLSEC:
1109 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1110 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1112 case MONO_PATCH_INFO_SWITCH:
1113 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1114 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1115 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1116 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1118 case MONO_PATCH_INFO_RGCTX_FETCH:
1119 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1120 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1121 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1122 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1124 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1125 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1126 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1128 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1129 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1130 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1132 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1133 MonoGSharedVtMethodInfo *info;
1134 MonoGSharedVtMethodInfo *oinfo;
1137 oinfo = patch_info->data.gsharedvt_method;
1138 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1139 res->data.gsharedvt_method = info;
1140 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1141 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1142 for (i = 0; i < oinfo->num_entries; ++i) {
1143 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1144 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1146 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1148 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1149 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1152 case MONO_PATCH_INFO_VIRT_METHOD: {
1153 MonoJumpInfoVirtMethod *info;
1154 MonoJumpInfoVirtMethod *oinfo;
1156 oinfo = patch_info->data.virt_method;
1157 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1158 res->data.virt_method = info;
1159 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1170 mono_patch_info_hash (gconstpointer data)
1172 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1175 case MONO_PATCH_INFO_RVA:
1176 case MONO_PATCH_INFO_LDSTR:
1177 case MONO_PATCH_INFO_LDTOKEN:
1178 case MONO_PATCH_INFO_DECLSEC:
1179 return (ji->type << 8) | ji->data.token->token;
1180 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1181 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1182 case MONO_PATCH_INFO_INTERNAL_METHOD:
1183 return (ji->type << 8) | g_str_hash (ji->data.name);
1184 case MONO_PATCH_INFO_VTABLE:
1185 case MONO_PATCH_INFO_CLASS:
1186 case MONO_PATCH_INFO_IID:
1187 case MONO_PATCH_INFO_ADJUSTED_IID:
1188 case MONO_PATCH_INFO_METHODCONST:
1189 case MONO_PATCH_INFO_METHOD:
1190 case MONO_PATCH_INFO_METHOD_JUMP:
1191 case MONO_PATCH_INFO_IMAGE:
1192 case MONO_PATCH_INFO_ICALL_ADDR:
1193 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1194 case MONO_PATCH_INFO_FIELD:
1195 case MONO_PATCH_INFO_SFLDA:
1196 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1197 case MONO_PATCH_INFO_METHOD_RGCTX:
1198 case MONO_PATCH_INFO_SIGNATURE:
1199 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1200 case MONO_PATCH_INFO_AOT_JIT_INFO:
1201 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1202 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1203 return (ji->type << 8) | (gssize)ji->data.target;
1204 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1205 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1206 case MONO_PATCH_INFO_RGCTX_FETCH:
1207 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1208 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1210 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1212 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1213 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1214 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1215 case MONO_PATCH_INFO_GC_NURSERY_START:
1216 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1217 case MONO_PATCH_INFO_GOT_OFFSET:
1218 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1219 case MONO_PATCH_INFO_AOT_MODULE:
1220 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1221 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1222 return (ji->type << 8);
1223 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1224 return (ji->type << 8) | (ji->data.index);
1225 case MONO_PATCH_INFO_SWITCH:
1226 return (ji->type << 8) | ji->data.table->table_size;
1227 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1228 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1229 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1230 /* Hash on the selector name */
1231 return g_str_hash (ji->data.target);
1232 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1233 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1234 case MONO_PATCH_INFO_LDSTR_LIT:
1235 return g_str_hash (ji->data.target);
1236 case MONO_PATCH_INFO_VIRT_METHOD: {
1237 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1239 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1241 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1242 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1243 return (ji->type << 8) | g_str_hash (ji->data.target);
1244 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1245 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1247 printf ("info type: %d\n", ji->type);
1248 mono_print_ji (ji); printf ("\n");
1249 g_assert_not_reached ();
1255 * mono_patch_info_equal:
1257 * This might fail to recognize equivalent patches, i.e. floats, so its only
1258 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1262 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1264 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1265 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1267 if (ji1->type != ji2->type)
1270 switch (ji1->type) {
1271 case MONO_PATCH_INFO_RVA:
1272 case MONO_PATCH_INFO_LDSTR:
1273 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1274 case MONO_PATCH_INFO_LDTOKEN:
1275 case MONO_PATCH_INFO_DECLSEC:
1276 if ((ji1->data.token->image != ji2->data.token->image) ||
1277 (ji1->data.token->token != ji2->data.token->token) ||
1278 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1279 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1280 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1283 case MONO_PATCH_INFO_INTERNAL_METHOD:
1284 return g_str_equal (ji1->data.name, ji2->data.name);
1285 case MONO_PATCH_INFO_RGCTX_FETCH:
1286 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1287 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1288 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1290 return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
1292 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1293 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1294 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1296 return c1->sig == c2->sig && c1->method == c2->method;
1298 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1299 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1300 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1301 return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->is_virtual == ji2->data.del_tramp->is_virtual;
1302 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1303 return ji1->data.index == ji2->data.index;
1304 case MONO_PATCH_INFO_VIRT_METHOD:
1305 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1306 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1307 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1308 if (ji1->data.target == ji2->data.target)
1310 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1311 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1312 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1314 if (ji1->data.target != ji2->data.target)
1323 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1325 unsigned char *ip = patch_info->ip.i + code;
1326 gconstpointer target = NULL;
1330 switch (patch_info->type) {
1331 case MONO_PATCH_INFO_BB:
1333 * FIXME: This could be hit for methods without a prolog. Should use -1
1334 * but too much code depends on a 0 initial value.
1336 //g_assert (patch_info->data.bb->native_offset);
1337 target = patch_info->data.bb->native_offset + code;
1339 case MONO_PATCH_INFO_ABS:
1340 target = patch_info->data.target;
1342 case MONO_PATCH_INFO_LABEL:
1343 target = patch_info->data.inst->inst_c0 + code;
1345 case MONO_PATCH_INFO_IP:
1348 case MONO_PATCH_INFO_METHOD_REL:
1349 target = code + patch_info->data.offset;
1351 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1352 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1354 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1355 g_assert_not_reached ();
1357 target = mono_icall_get_wrapper (mi);
1360 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1361 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1362 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1364 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1365 g_assert_not_reached ();
1370 case MONO_PATCH_INFO_METHOD_JUMP:
1371 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1372 if (!mono_error_ok (error))
1375 case MONO_PATCH_INFO_METHOD:
1376 if (patch_info->data.method == method) {
1379 /* get the trampoline to the method from the domain */
1380 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1381 if (!mono_error_ok (error))
1385 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1388 mono_domain_lock (domain);
1389 if (!domain_jit_info (domain)->method_code_hash)
1390 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1391 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1393 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1394 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1396 mono_domain_unlock (domain);
1400 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1401 g_assert (mono_threads_is_coop_enabled ());
1402 target = (gpointer)&mono_polling_required;
1404 case MONO_PATCH_INFO_SWITCH: {
1405 gpointer *jump_table;
1407 if (method && method->dynamic) {
1408 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1410 if (mono_aot_only) {
1411 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1413 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1417 for (i = 0; i < patch_info->data.table->table_size; i++) {
1418 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1421 target = jump_table;
1424 case MONO_PATCH_INFO_METHODCONST:
1425 case MONO_PATCH_INFO_CLASS:
1426 case MONO_PATCH_INFO_IMAGE:
1427 case MONO_PATCH_INFO_FIELD:
1428 case MONO_PATCH_INFO_SIGNATURE:
1429 case MONO_PATCH_INFO_AOT_MODULE:
1430 target = patch_info->data.target;
1432 case MONO_PATCH_INFO_IID:
1433 mono_class_init (patch_info->data.klass);
1434 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1436 case MONO_PATCH_INFO_ADJUSTED_IID:
1437 mono_class_init (patch_info->data.klass);
1438 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1440 case MONO_PATCH_INFO_VTABLE:
1441 target = mono_class_vtable (domain, patch_info->data.klass);
1444 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1445 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1447 if (del_tramp->is_virtual)
1448 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1450 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1453 case MONO_PATCH_INFO_SFLDA: {
1454 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1456 if (mono_class_field_is_special_static (patch_info->data.field)) {
1457 gpointer addr = NULL;
1459 mono_domain_lock (domain);
1460 if (domain->special_static_fields)
1461 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1462 mono_domain_unlock (domain);
1468 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1469 /* Done by the generated code */
1473 if (!mono_runtime_class_init_full (vtable, error)) {
1478 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1481 case MONO_PATCH_INFO_RVA: {
1482 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1485 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1486 target = mono_image_rva_map (patch_info->data.token->image, rva);
1489 case MONO_PATCH_INFO_R4:
1490 case MONO_PATCH_INFO_R8:
1491 target = patch_info->data.target;
1493 case MONO_PATCH_INFO_EXC_NAME:
1494 target = patch_info->data.name;
1496 case MONO_PATCH_INFO_LDSTR:
1498 mono_ldstr_checked (domain, patch_info->data.token->image,
1499 mono_metadata_token_index (patch_info->data.token->token), error);
1501 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1503 MonoClass *handle_class;
1505 handle = mono_ldtoken_checked (patch_info->data.token->image,
1506 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1507 if (!mono_error_ok (error))
1509 mono_class_init (handle_class);
1510 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1512 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1513 if (!mono_error_ok (error))
1517 case MONO_PATCH_INFO_LDTOKEN: {
1519 MonoClass *handle_class;
1521 handle = mono_ldtoken_checked (patch_info->data.token->image,
1522 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1523 if (!mono_error_ok (error))
1524 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1525 mono_class_init (handle_class);
1530 case MONO_PATCH_INFO_DECLSEC:
1531 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1533 case MONO_PATCH_INFO_ICALL_ADDR:
1534 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1535 /* run_cctors == 0 -> AOT */
1536 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1537 const char *exc_class;
1538 const char *exc_arg;
1541 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1543 if (mono_aot_only) {
1544 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1547 g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info->data.method, TRUE));
1553 target = mono_lookup_internal_call (patch_info->data.method);
1555 if (!target && run_cctors)
1556 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1559 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1560 target = mono_thread_interruption_request_flag ();
1562 case MONO_PATCH_INFO_METHOD_RGCTX: {
1563 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1566 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1569 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1570 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1572 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1575 case MONO_PATCH_INFO_BB_OVF:
1576 case MONO_PATCH_INFO_EXC_OVF:
1577 case MONO_PATCH_INFO_GOT_OFFSET:
1578 case MONO_PATCH_INFO_NONE:
1580 case MONO_PATCH_INFO_RGCTX_FETCH: {
1581 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1583 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1586 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1587 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1589 /* AOT, not needed */
1592 target = mono_arch_get_seq_point_info (domain, code);
1595 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1596 int card_table_shift_bits;
1597 gpointer card_table_mask;
1599 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1602 case MONO_PATCH_INFO_GC_NURSERY_START: {
1606 target = mono_gc_get_nursery (&shift_bits, &size);
1609 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1613 mono_gc_get_nursery (&shift_bits, &size);
1615 target = (gpointer)(mgreg_t)shift_bits;
1618 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1619 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1622 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1626 case MONO_PATCH_INFO_LDSTR_LIT: {
1630 len = strlen ((const char *)patch_info->data.target);
1631 s = (char *)mono_domain_alloc0 (domain, len + 1);
1632 memcpy (s, patch_info->data.target, len);
1637 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1638 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1640 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1641 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1643 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1644 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1646 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1647 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1652 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1653 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1657 g_assert_not_reached ();
1660 return (gpointer)target;
1664 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1666 MonoGenericInst *inst;
1669 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1671 if (context && context->class_inst) {
1672 inst = context->class_inst;
1673 for (i = 0; i < inst->type_argc; ++i) {
1674 MonoType *type = inst->type_argv [i];
1676 if (mini_is_gsharedvt_gparam (type))
1677 gsctx->is_gsharedvt = TRUE;
1680 if (context && context->method_inst) {
1681 inst = context->method_inst;
1683 for (i = 0; i < inst->type_argc; ++i) {
1684 MonoType *type = inst->type_argv [i];
1686 if (mini_is_gsharedvt_gparam (type))
1687 gsctx->is_gsharedvt = TRUE;
1693 * LOCKING: Acquires the jit code hash lock.
1696 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1699 static gboolean inited = FALSE;
1700 static int lookups = 0;
1701 static int failed_lookups = 0;
1703 mono_domain_jit_code_hash_lock (domain);
1704 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1705 if (!ji && shared) {
1706 /* Try generic sharing */
1707 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1708 if (ji && !ji->has_generic_jit_info)
1711 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1712 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1720 mono_domain_jit_code_hash_unlock (domain);
1726 lookup_method (MonoDomain *domain, MonoMethod *method)
1731 ji = mini_lookup_method (domain, method, NULL);
1734 if (!mono_method_is_generic_sharable (method, FALSE))
1736 shared = mini_get_shared_method (method);
1737 ji = mini_lookup_method (domain, method, shared);
1744 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1746 return lookup_method (domain, method);
1750 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1755 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1756 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1758 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
1759 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1762 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
1763 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1766 mono_class_init (klass);
1771 static FILE* perf_map_file;
1774 mono_enable_jit_map (void)
1776 if (!perf_map_file) {
1778 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1780 perf_map_file = fopen (name, "w");
1785 mono_emit_jit_tramp (void *start, int size, const char *desc)
1788 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1792 mono_emit_jit_map (MonoJitInfo *jinfo)
1794 if (perf_map_file) {
1795 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1796 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1802 mono_jit_map_is_enabled (void)
1804 return perf_map_file != NULL;
1810 no_gsharedvt_in_wrapper (void)
1812 g_assert_not_reached ();
1818 When a JIT request is made, we check if there's an outstanding one for that method and, if it exits, put the thread to sleep.
1819 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1820 Dependency management in this case is too complex to justify implementing it.
1822 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1825 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1826 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1827 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1828 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1833 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1834 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1835 int threads_waiting; /* Number of threads waiting on this job */
1836 gboolean has_cond; /* True if @cond was initialized */
1837 gboolean done; /* True if the method finished JIT'ing */
1838 MonoCoopCond cond; /* Cond sleeping threads wait one */
1839 } JitCompilationEntry;
1842 GPtrArray *in_flight_methods; //JitCompilationEntry*
1844 } JitCompilationData;
1846 static JitCompilationData compilation_data;
1847 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1850 mini_jit_init_job_control (void)
1852 mono_coop_mutex_init (&compilation_data.lock);
1853 compilation_data.in_flight_methods = g_ptr_array_new ();
1857 lock_compilation_data (void)
1859 mono_coop_mutex_lock (&compilation_data.lock);
1863 unlock_compilation_data (void)
1865 mono_coop_mutex_unlock (&compilation_data.lock);
1868 static JitCompilationEntry*
1869 find_method (MonoMethod *method, MonoDomain *domain)
1872 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1873 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1874 if (e->method == method && e->domain == domain)
1882 add_current_thread (MonoJitTlsData *jit_tls)
1884 ++jit_tls->active_jit_methods;
1888 unref_jit_entry (JitCompilationEntry *entry)
1891 if (entry->ref_count)
1893 if (entry->has_cond)
1894 mono_coop_cond_destroy (&entry->cond);
1899 * Returns true if this method waited successfully for another thread to JIT it
1902 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1904 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1905 JitCompilationEntry *entry;
1907 static gboolean inited;
1909 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1910 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1911 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1912 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1916 lock_compilation_data ();
1918 if (!(entry = find_method (method, domain))) {
1919 entry = g_new0 (JitCompilationEntry, 1);
1920 entry->method = method;
1921 entry->domain = domain;
1922 entry->compilation_count = entry->ref_count = 1;
1923 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1924 g_assert (find_method (method, domain) == entry);
1925 add_current_thread (jit_tls);
1927 unlock_compilation_data ();
1929 } else if (jit_tls->active_jit_methods > 0) {
1930 //We can't suspend the current thread if it's already JITing a method.
1931 //Dependency management is too compilated and we want to get rid of this anyways.
1932 ++entry->compilation_count;
1933 ++jit_methods_multiple;
1934 ++jit_tls->active_jit_methods;
1936 unlock_compilation_data ();
1939 ++jit_methods_waited;
1942 if (!entry->has_cond) {
1943 mono_coop_cond_init (&entry->cond);
1944 entry->has_cond = TRUE;
1948 ++entry->threads_waiting;
1950 g_assert (entry->has_cond);
1951 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1952 --entry->threads_waiting;
1955 unref_jit_entry (entry);
1956 unlock_compilation_data ();
1959 ++jit_spurious_wakeups;
1966 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1968 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1970 lock_compilation_data ();
1972 g_assert (jit_tls->active_jit_methods > 0);
1973 --jit_tls->active_jit_methods;
1975 JitCompilationEntry *entry = find_method (method, target_domain);
1976 g_assert (entry); // It would be weird to fail
1979 if (entry->threads_waiting) {
1980 g_assert (entry->has_cond);
1981 mono_coop_cond_broadcast (&entry->cond);
1984 if (--entry->compilation_count == 0) {
1985 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1986 unref_jit_entry (entry);
1989 unlock_compilation_data ();
1994 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1996 MonoDomain *target_domain, *domain = mono_domain_get ();
1998 gpointer code = NULL, p;
2000 MonoJitICallInfo *callinfo = NULL;
2001 WrapperInfo *winfo = NULL;
2005 #ifdef ENABLE_INTERPRETER
2006 if (mono_use_interpreter && !jit_only) {
2007 code = mono_interp_create_method_pointer (method, error);
2014 /* Should be handled by the caller */
2015 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2018 * ICALL wrappers are handled specially, since there is only one copy of them
2019 * shared by all appdomains.
2021 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2022 winfo = mono_marshal_get_wrapper_info (method);
2023 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2024 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2025 g_assert (callinfo);
2027 /* Must be domain neutral since there is only one copy */
2028 opt |= MONO_OPT_SHARED;
2030 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2031 opt &= ~MONO_OPT_SHARED;
2034 if (opt & MONO_OPT_SHARED)
2035 target_domain = mono_get_root_domain ();
2037 target_domain = domain;
2039 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2040 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2043 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2044 MonoGenericContext *ctx = NULL;
2045 if (method->is_inflated)
2046 ctx = mono_method_get_context (method);
2047 method = info->d.synchronized_inner.method;
2049 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2050 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2056 info = lookup_method (target_domain, method);
2058 /* We can't use a domain specific method in another domain */
2059 if (! ((domain != target_domain) && !info->domain_neutral)) {
2062 mono_jit_stats.methods_lookups++;
2063 vtable = mono_class_vtable_full (domain, method->klass, error);
2067 if (!mono_runtime_class_init_full (vtable, error))
2069 return mono_create_ftnptr (target_domain, info->code_start);
2073 #ifdef MONO_USE_AOT_COMPILER
2074 if (opt & MONO_OPT_AOT) {
2075 MonoDomain *domain = NULL;
2077 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2078 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2080 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
2081 /* AOT'd wrappers for interp must be owned by root domain */
2082 domain = mono_get_root_domain ();
2086 domain = mono_domain_get ();
2088 mono_class_init (method->klass);
2090 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2093 if (mono_gc_is_critical_method (method)) {
2095 * The suspend code needs to be able to lookup these methods by ip in async context,
2096 * so preload their jit info.
2098 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2103 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2104 * This is not a problem, since it will be initialized when the method is first
2105 * called by init_method ().
2107 if (!mono_llvm_only) {
2108 vtable = mono_class_vtable (domain, method->klass);
2110 if (!mono_runtime_class_init_full (vtable, error))
2119 if (!code && mono_llvm_only) {
2120 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2121 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2123 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2125 * These wrappers are only created for signatures which are in the program, but
2126 * sometimes we load methods too eagerly and have to create them even if they
2127 * will never be called.
2129 return no_gsharedvt_in_wrapper;
2135 if (wait_or_register_method_to_compile (method, target_domain))
2137 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2138 unregister_method_for_compile (method, target_domain);
2140 if (!mono_error_ok (error))
2143 if (!code && mono_llvm_only) {
2144 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2145 g_assert_not_reached ();
2151 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2155 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2157 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2161 p = mono_create_ftnptr (target_domain, code);
2164 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2165 mono_loader_lock ();
2167 if (!callinfo->wrapper) {
2168 callinfo->wrapper = p;
2169 mono_register_jit_icall_wrapper (callinfo, p);
2172 mono_loader_unlock ();
2179 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2183 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2188 * mono_jit_compile_method_jit_only:
2190 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2193 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2197 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2201 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2203 invalidated_delegate_trampoline (char *desc)
2205 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2206 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2212 * mono_jit_free_method:
2214 * Free all memory allocated by the JIT for METHOD.
2217 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2219 MonoJitDynamicMethodInfo *ji;
2220 gboolean destroy = TRUE;
2221 GHashTableIter iter;
2222 MonoJumpList *jlist;
2224 g_assert (method->dynamic);
2226 mono_domain_lock (domain);
2227 ji = mono_dynamic_code_hash_lookup (domain, method);
2228 mono_domain_unlock (domain);
2233 mono_debug_remove_method (method, domain);
2234 mono_lldb_remove_method (domain, method, ji);
2236 mono_domain_lock (domain);
2237 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2238 mono_domain_jit_code_hash_lock (domain);
2239 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2240 mono_domain_jit_code_hash_unlock (domain);
2241 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2243 /* requires the domain lock - took above */
2244 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2246 /* Remove jump targets in this method */
2247 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2248 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2249 GSList *tmp, *remove;
2252 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2253 guint8 *ip = (guint8 *)tmp->data;
2255 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2256 remove = g_slist_prepend (remove, tmp);
2258 for (tmp = remove; tmp; tmp = tmp->next) {
2259 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2261 g_slist_free (remove);
2263 mono_domain_unlock (domain);
2265 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2266 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2268 * Instead of freeing the code, change it to call an error routine
2269 * so people can fix their code.
2271 char *type = mono_type_full_name (&method->klass->byval_arg);
2272 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2275 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2281 * This needs to be done before freeing code_mp, since the code address is the
2282 * key in the table, so if we free the code_mp first, another thread can grab the
2283 * same code address and replace our entry in the table.
2285 mono_jit_info_table_remove (domain, ji->ji);
2288 mono_code_manager_destroy (ji->code_mp);
2293 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2295 MonoDomain *target_domain;
2298 if (default_opt & MONO_OPT_SHARED)
2299 target_domain = mono_get_root_domain ();
2301 target_domain = domain;
2303 info = lookup_method (target_domain, method);
2305 /* We can't use a domain specific method in another domain */
2306 if (! ((domain != target_domain) && !info->domain_neutral)) {
2307 mono_jit_stats.methods_lookups++;
2310 return info->code_start;
2319 static guint32 bisect_opt = 0;
2320 static GHashTable *bisect_methods_hash = NULL;
2323 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2326 char method_name [2048];
2329 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2330 g_assert (bisect_methods_hash);
2332 file = fopen (method_list_filename, "r");
2335 while (fgets (method_name, sizeof (method_name), file)) {
2336 size_t len = strlen (method_name);
2338 g_assert (method_name [len - 1] == '\n');
2339 method_name [len - 1] = 0;
2340 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2342 g_assert (feof (file));
2345 gboolean mono_do_single_method_regression = FALSE;
2346 guint32 mono_single_method_regression_opt = 0;
2347 MonoMethod *mono_current_single_method;
2348 GSList *mono_single_method_list;
2349 GHashTable *mono_single_method_hash;
2352 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2356 if (bisect_methods_hash) {
2357 char *name = mono_method_full_name (method, TRUE);
2358 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2361 return default_opt | bisect_opt;
2363 if (!mono_do_single_method_regression)
2365 if (!mono_current_single_method) {
2366 if (!mono_single_method_hash)
2367 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2368 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2369 g_hash_table_insert (mono_single_method_hash, method, method);
2370 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2374 if (method == mono_current_single_method)
2375 return mono_single_method_regression_opt;
2380 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2382 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2387 gpointer compiled_method;
2388 gpointer runtime_invoke;
2390 MonoDynCallInfo *dyn_call_info;
2391 MonoClass *ret_box_class;
2392 MonoMethodSignature *sig;
2393 gboolean gsharedvt_invoke;
2394 gpointer *wrapper_arg;
2395 } RuntimeInvokeInfo;
2397 static RuntimeInvokeInfo*
2398 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2401 RuntimeInvokeInfo *info;
2403 info = g_new0 (RuntimeInvokeInfo, 1);
2404 info->compiled_method = compiled_method;
2405 if (mono_llvm_only && method->string_ctor)
2406 info->sig = mono_marshal_get_string_ctor_signature (method);
2408 info->sig = mono_method_signature (method);
2410 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2411 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2412 if (!mono_error_ok (error))
2414 g_assert (info->vtable);
2416 MonoMethodSignature *sig = info->sig;
2420 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2421 * in full-aot mode, so we use a slower, but more generic wrapper if
2422 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2424 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2425 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2426 gboolean supported = TRUE;
2429 if (method->string_ctor)
2430 sig = mono_marshal_get_string_ctor_signature (method);
2432 for (i = 0; i < sig->param_count; ++i) {
2433 MonoType *t = sig->params [i];
2435 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2439 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2443 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2447 ret_type = sig->ret;
2448 switch (ret_type->type) {
2449 case MONO_TYPE_VOID:
2461 case MONO_TYPE_BOOLEAN:
2462 case MONO_TYPE_CHAR:
2465 info->ret_box_class = mono_class_from_mono_type (ret_type);
2468 info->ret_box_class = mono_defaults.int_class;
2470 case MONO_TYPE_STRING:
2471 case MONO_TYPE_CLASS:
2472 case MONO_TYPE_ARRAY:
2473 case MONO_TYPE_SZARRAY:
2474 case MONO_TYPE_OBJECT:
2476 case MONO_TYPE_GENERICINST:
2477 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2478 info->ret_box_class = mono_class_from_mono_type (ret_type);
2480 case MONO_TYPE_VALUETYPE:
2481 info->ret_box_class = mono_class_from_mono_type (ret_type);
2484 g_assert_not_reached ();
2488 if (!info->dyn_call_info) {
2489 if (mono_llvm_only) {
2490 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2491 g_assert_not_reached ();
2493 info->gsharedvt_invoke = TRUE;
2494 if (!callee_gsharedvt) {
2495 /* Invoke a gsharedvt out wrapper instead */
2496 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2497 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2499 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2500 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2502 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2503 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2504 g_free (wrapper_sig);
2506 info->compiled_method = mono_jit_compile_method (wrapper, error);
2507 if (!mono_error_ok (error)) {
2512 /* Gsharedvt methods can be invoked the same way */
2513 /* The out wrapper has the same signature as the compiled gsharedvt method */
2514 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2516 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2518 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2519 g_free (wrapper_sig);
2522 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2523 if (!mono_error_ok (error)) {
2533 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2535 MonoMethodSignature *sig = info->sig;
2536 MonoDomain *domain = mono_domain_get ();
2537 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2539 gpointer retval_ptr;
2540 guint8 retval [256];
2541 gpointer *param_refs;
2546 g_assert (info->gsharedvt_invoke);
2549 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2550 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2551 * signatures, so we only have to generate runtime invoke wrappers for these
2553 * This code also handles invocation of gsharedvt methods directly, no
2554 * out wrappers are used in that case.
2556 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2557 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2560 * The runtime invoke wrappers expects pointers to primitive types, so have to
2564 args [pindex ++] = &obj;
2565 if (sig->ret->type != MONO_TYPE_VOID) {
2566 retval_ptr = (gpointer)&retval;
2567 args [pindex ++] = &retval_ptr;
2569 for (i = 0; i < sig->param_count; ++i) {
2570 MonoType *t = sig->params [i];
2572 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2573 MonoClass *klass = mono_class_from_mono_type (t);
2574 guint8 *nullable_buf;
2577 size = mono_class_value_size (klass, NULL);
2578 nullable_buf = g_alloca (size);
2579 g_assert (nullable_buf);
2581 /* The argument pointed to by params [i] is either a boxed vtype or null */
2582 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2583 params [i] = nullable_buf;
2586 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2587 param_refs [i] = params [i];
2588 params [i] = &(param_refs [i]);
2590 args [pindex ++] = ¶ms [i];
2592 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2593 args [pindex ++] = &info->wrapper_arg;
2595 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2597 runtime_invoke (NULL, args, exc, info->compiled_method);
2601 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2602 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2604 return *(MonoObject**)retval;
2608 * mono_jit_runtime_invoke:
2609 * \param method: the method to invoke
2610 * \param obj: this pointer
2611 * \param params: array of parameter values.
2612 * \param exc: Set to the exception raised in the managed method.
2613 * \param error: error or caught exception object
2614 * If \p exc is NULL, \p error is thrown instead.
2615 * If coop is enabled, \p exc argument is ignored -
2616 * all exceptions are caught and propagated through \p error
2619 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2621 MonoMethod *invoke, *callee;
2622 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2623 MonoDomain *domain = mono_domain_get ();
2624 MonoJitDomainInfo *domain_info;
2625 RuntimeInvokeInfo *info, *info2;
2626 MonoJitInfo *ji = NULL;
2627 gboolean callee_gsharedvt = FALSE;
2629 #ifdef ENABLE_INTERPRETER
2630 if (mono_use_interpreter)
2631 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2636 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2637 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2641 domain_info = domain_jit_info (domain);
2643 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2646 if (mono_security_core_clr_enabled ()) {
2648 * This might be redundant since mono_class_vtable () already does this,
2649 * but keep it just in case for moonlight.
2651 mono_class_setup_vtable (method->klass);
2652 if (mono_class_has_failure (method->klass)) {
2653 mono_error_set_for_class_failure (error, method->klass);
2655 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2660 gpointer compiled_method;
2663 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2664 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2666 * Array Get/Set/Address methods. The JIT implements them using inline code
2667 * inside the runtime invoke wrappers, so no need to compile them.
2669 if (mono_aot_only) {
2671 * Call a wrapper, since the runtime invoke wrapper was not generated.
2673 MonoMethod *wrapper;
2675 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2676 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2684 compiled_method = mono_jit_compile_method (callee, error);
2685 if (!compiled_method) {
2686 g_assert (!mono_error_ok (error));
2690 if (mono_llvm_only) {
2691 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2692 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2693 if (callee_gsharedvt)
2694 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2697 if (!callee_gsharedvt)
2698 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2700 compiled_method = NULL;
2703 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2704 if (!mono_error_ok (error))
2707 mono_domain_lock (domain);
2708 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2709 mono_domain_unlock (domain);
2717 * We need this here because mono_marshal_get_runtime_invoke can place
2718 * the helper method in System.Object and not the target class.
2720 if (!mono_runtime_class_init_full (info->vtable, error)) {
2722 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2726 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2727 we always catch the exception and propagate it through the MonoError */
2728 gboolean catchExcInMonoError =
2729 (exc == NULL) && mono_threads_is_coop_enabled ();
2730 MonoObject *invoke_exc = NULL;
2731 if (catchExcInMonoError)
2734 /* The wrappers expect this to be initialized to NULL */
2738 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2739 if (info->dyn_call_info) {
2740 MonoMethodSignature *sig = mono_method_signature (method);
2742 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2745 guint8 retval [256];
2747 if (!dyn_runtime_invoke) {
2748 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2749 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2750 if (!mono_error_ok (error))
2754 /* Convert the arguments to the format expected by start_dyn_call () */
2755 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2758 args [pindex ++] = &obj;
2759 for (i = 0; i < sig->param_count; ++i) {
2760 MonoType *t = sig->params [i];
2763 args [pindex ++] = ¶ms [i];
2764 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2765 args [pindex ++] = ¶ms [i];
2767 args [pindex ++] = params [i];
2771 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2773 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2775 dyn_runtime_invoke (buf, exc, info->compiled_method);
2776 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2778 if (catchExcInMonoError && *exc != NULL) {
2779 mono_error_set_exception_instance (error, (MonoException*) *exc);
2783 if (info->ret_box_class)
2784 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2786 return *(MonoObject**)retval;
2792 if (mono_llvm_only) {
2793 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2797 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2799 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2801 if (catchExcInMonoError && *exc != NULL)
2802 mono_error_set_exception_instance (error, (MonoException*) *exc);
2811 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2814 * mini_llvmonly_initial_imt_tramp:
2816 * This function is called the first time a call is made through an IMT trampoline.
2817 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2820 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2822 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2827 mono_vtable_build_imt_slot (info->vtable, info->slot);
2829 imt = (gpointer*)info->vtable;
2830 imt -= MONO_IMT_SIZE;
2832 /* Return what the real IMT trampoline returns */
2833 ftndesc = imt [info->slot];
2836 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2837 /* Happens when the imt slot contains only a generic virtual method */
2839 return func ((gpointer *)ftndesc [1], imt_method);
2842 /* This is called indirectly through an imt slot. */
2844 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2848 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2849 while (arg [i] && arg [i] != imt_method)
2856 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2858 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2860 //g_assert (arg [0] == imt_method);
2865 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2867 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2868 if (arg [0] == imt_method)
2875 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2877 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2878 if (arg [0] == imt_method)
2880 else if (arg [2] == imt_method)
2887 * A version of the imt trampoline used for generic virtual/variant iface methods.
2888 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2889 * in the search table. The original JIT code had a 'fallback' trampoline it could
2890 * call, but we can't do that, so we just return NULL, and the compiled code
2894 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2898 while (arg [i] && arg [i] != imt_method)
2907 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2911 int i, index, real_count;
2912 gboolean virtual_generic = FALSE;
2915 * Create an array which is passed to the imt trampoline functions.
2916 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2920 for (i = 0; i < count; ++i) {
2921 MonoIMTCheckItem *item = imt_entries [i];
2923 if (item->is_equals)
2925 if (item->has_target_code)
2926 virtual_generic = TRUE;
2930 * Initialize all vtable entries reachable from this imt slot, so the compiled
2931 * code doesn't have to check it.
2933 for (i = 0; i < count; ++i) {
2934 MonoIMTCheckItem *item = imt_entries [i];
2937 if (!item->is_equals || item->has_target_code)
2939 vt_slot = item->value.vtable_slot;
2940 mono_init_vtable_slot (vtable, vt_slot);
2943 /* Save the entries into an array */
2944 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2946 for (i = 0; i < count; ++i) {
2947 MonoIMTCheckItem *item = imt_entries [i];
2949 if (!item->is_equals)
2952 g_assert (item->key);
2953 buf [(index * 2)] = item->key;
2954 if (item->has_target_code)
2955 buf [(index * 2) + 1] = item->value.target_code;
2957 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2960 buf [(index * 2)] = NULL;
2961 buf [(index * 2) + 1] = fail_tramp;
2964 * Return a function descriptor for a C function with 'buf' as its argument.
2965 * It will by called by JITted code.
2967 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2968 switch (real_count) {
2970 res [0] = mono_llvmonly_imt_tramp_1;
2973 res [0] = mono_llvmonly_imt_tramp_2;
2976 res [0] = mono_llvmonly_imt_tramp_3;
2979 res [0] = mono_llvmonly_imt_tramp;
2982 if (virtual_generic || fail_tramp)
2983 res [0] = mono_llvmonly_fallback_imt_tramp;
2989 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2991 MonoException *exc = NULL;
2993 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2994 MONO_SIG_HANDLER_GET_CONTEXT;
2996 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2998 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3000 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3001 if (mono_arch_is_int_overflow (ctx, info))
3003 * The spec says this throws ArithmeticException, but MS throws the derived
3004 * OverflowException.
3006 exc = mono_get_exception_overflow ();
3008 exc = mono_get_exception_divide_by_zero ();
3010 exc = mono_get_exception_divide_by_zero ();
3014 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3017 mono_handle_native_crash ("SIGFPE", ctx, info);
3018 if (mono_do_crash_chaining) {
3019 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3024 mono_arch_handle_exception (ctx, exc);
3027 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3030 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3032 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3033 MONO_SIG_HANDLER_GET_CONTEXT;
3035 if (mono_runtime_get_no_exec ())
3039 mono_handle_native_crash ("SIGILL", ctx, info);
3040 if (mono_do_crash_chaining) {
3041 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3045 g_assert_not_reached ();
3048 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3049 #define HAVE_SIG_INFO
3052 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3055 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3056 gpointer fault_addr = NULL;
3057 #ifdef HAVE_SIG_INFO
3058 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3062 MONO_SIG_HANDLER_GET_CONTEXT;
3064 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3065 if (mono_arch_is_single_step_event (info, ctx)) {
3066 mono_debugger_agent_single_step_event (ctx);
3068 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3069 mono_debugger_agent_breakpoint_hit (ctx);
3074 #if defined(HAVE_SIG_INFO)
3075 #if !defined(HOST_WIN32)
3076 fault_addr = info->si_addr;
3077 if (mono_aot_is_pagefault (info->si_addr)) {
3078 mono_aot_handle_pagefault (info->si_addr);
3083 /* The thread might no be registered with the runtime */
3084 if (!mono_domain_get () || !jit_tls) {
3085 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3087 mono_handle_native_crash ("SIGSEGV", ctx, info);
3088 if (mono_do_crash_chaining) {
3089 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3095 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3097 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3098 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3101 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3102 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3103 fault_addr = info->si_addr;
3104 if (fault_addr == NULL) {
3107 mono_sigctx_to_monoctx (ctx, &mctx);
3109 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3113 if (jit_tls->stack_size &&
3114 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3116 * The hard-guard page has been hit: there is not much we can do anymore
3117 * Print a hopefully clear message and abort.
3119 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3120 g_assert_not_reached ();
3122 /* The original handler might not like that it is executed on an altstack... */
3123 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3126 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3131 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3134 mono_handle_native_crash ("SIGSEGV", ctx, info);
3136 if (mono_do_crash_chaining) {
3137 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3142 mono_arch_handle_exception (ctx, NULL);
3146 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3149 MONO_SIG_HANDLER_GET_CONTEXT;
3151 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3153 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3155 mono_arch_handle_exception (ctx, exc);
3157 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3160 #ifndef DISABLE_REMOTING
3161 /* mono_jit_create_remoting_trampoline:
3162 * @method: pointer to the method info
3164 * Creates a trampoline which calls the remoting functions. This
3165 * is used in the vtable of transparent proxies.
3167 * Returns: a pointer to the newly created code
3170 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3173 guint8 *addr = NULL;
3177 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3178 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3182 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3183 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3184 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3187 addr = (guint8 *)mono_compile_method_checked (nm, error);
3188 return_val_if_nok (error, NULL);
3189 return mono_get_addr_from_ftnptr (addr);
3193 static G_GNUC_UNUSED void
3194 no_imt_trampoline (void)
3196 g_assert_not_reached ();
3199 static G_GNUC_UNUSED void
3200 no_vcall_trampoline (void)
3202 g_assert_not_reached ();
3205 static gpointer *vtable_trampolines;
3206 static int vtable_trampolines_size;
3209 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3211 int index = slot_index + MONO_IMT_SIZE;
3213 if (mono_llvm_only) {
3214 if (slot_index < 0) {
3215 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3216 // FIXME: Memory management
3217 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3218 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3221 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3223 mono_memory_barrier ();
3230 g_assert (slot_index >= - MONO_IMT_SIZE);
3231 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3233 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3237 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3238 while (new_size <= index)
3240 new_table = g_new0 (gpointer, new_size);
3242 if (vtable_trampolines)
3243 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3244 g_free (vtable_trampolines);
3245 mono_memory_barrier ();
3246 vtable_trampolines = (void **)new_table;
3247 vtable_trampolines_size = new_size;
3252 if (!vtable_trampolines [index])
3253 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3254 return vtable_trampolines [index];
3258 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3260 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3264 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3269 gpointer *imt = (gpointer*)vt;
3270 imt -= MONO_IMT_SIZE;
3272 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3276 is_callee_gsharedvt_variable (gpointer addr)
3279 gboolean callee_gsharedvt;
3281 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3283 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3284 if (callee_gsharedvt)
3285 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3286 return callee_gsharedvt;
3290 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3292 gpointer arg = NULL;
3294 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3295 arg = mini_method_get_rgctx (method);
3298 * Avoid adding gsharedvt in wrappers since they might not exist if
3299 * this delegate is called through a gsharedvt delegate invoke wrapper.
3300 * Instead, encode that the method is gsharedvt in del->extra_arg,
3301 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3303 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3304 g_assert ((((mgreg_t)arg) & 1) == 0);
3305 arg = (gpointer)(((mgreg_t)arg) | 1);
3311 mini_init_delegate (MonoDelegate *del)
3314 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3315 #ifdef ENABLE_INTERPRETER
3316 if (mono_use_interpreter)
3317 mono_interp_init_delegate (del);
3322 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3326 abs_offset = offset;
3328 abs_offset = - abs_offset;
3329 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3333 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3335 gboolean is_virtual_generic, is_interface, load_imt_reg;
3338 static guint8 **cache = NULL;
3339 static int cache_size = 0;
3344 if (MONO_TYPE_ISSTRUCT (sig->ret))
3347 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3348 is_interface = mono_class_is_interface (method->klass);
3349 load_imt_reg = is_virtual_generic || is_interface;
3352 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3354 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3356 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3357 g_assert (idx >= 0);
3359 /* Resize the cache to idx + 1 */
3360 if (cache_size < idx + 1) {
3362 if (cache_size < idx + 1) {
3364 int new_cache_size = idx + 1;
3366 new_cache = g_new0 (guint8*, new_cache_size);
3368 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3371 mono_memory_barrier ();
3373 cache_size = new_cache_size;
3381 /* FIXME Support more cases */
3382 if (mono_aot_only) {
3383 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3384 g_assert (cache [idx]);
3386 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3392 * mini_parse_debug_option:
3393 * @option: The option to parse.
3395 * Parses debug options for the mono runtime. The options are the same as for
3396 * the MONO_DEBUG environment variable.
3400 mini_parse_debug_option (const char *option)
3402 if (!strcmp (option, "handle-sigint"))
3403 debug_options.handle_sigint = TRUE;
3404 else if (!strcmp (option, "keep-delegates"))
3405 debug_options.keep_delegates = TRUE;
3406 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3407 debug_options.reverse_pinvoke_exceptions = TRUE;
3408 else if (!strcmp (option, "collect-pagefault-stats"))
3409 debug_options.collect_pagefault_stats = TRUE;
3410 else if (!strcmp (option, "break-on-unverified"))
3411 debug_options.break_on_unverified = TRUE;
3412 else if (!strcmp (option, "no-gdb-backtrace"))
3413 debug_options.no_gdb_backtrace = TRUE;
3414 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3415 debug_options.suspend_on_native_crash = TRUE;
3416 else if (!strcmp (option, "suspend-on-exception"))
3417 debug_options.suspend_on_exception = TRUE;
3418 else if (!strcmp (option, "suspend-on-unhandled"))
3419 debug_options.suspend_on_unhandled = TRUE;
3420 else if (!strcmp (option, "dont-free-domains"))
3421 mono_dont_free_domains = TRUE;
3422 else if (!strcmp (option, "dyn-runtime-invoke"))
3423 debug_options.dyn_runtime_invoke = TRUE;
3424 else if (!strcmp (option, "gdb"))
3425 debug_options.gdb = TRUE;
3426 else if (!strcmp (option, "lldb"))
3427 debug_options.lldb = TRUE;
3428 else if (!strcmp (option, "explicit-null-checks"))
3429 debug_options.explicit_null_checks = TRUE;
3430 else if (!strcmp (option, "gen-seq-points"))
3431 debug_options.gen_sdb_seq_points = TRUE;
3432 else if (!strcmp (option, "gen-compact-seq-points"))
3433 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3434 else if (!strcmp (option, "no-compact-seq-points"))
3435 debug_options.no_seq_points_compact_data = TRUE;
3436 else if (!strcmp (option, "single-imm-size"))
3437 debug_options.single_imm_size = TRUE;
3438 else if (!strcmp (option, "init-stacks"))
3439 debug_options.init_stacks = TRUE;
3440 else if (!strcmp (option, "casts"))
3441 debug_options.better_cast_details = TRUE;
3442 else if (!strcmp (option, "soft-breakpoints"))
3443 debug_options.soft_breakpoints = TRUE;
3444 else if (!strcmp (option, "check-pinvoke-callconv"))
3445 debug_options.check_pinvoke_callconv = TRUE;
3446 else if (!strcmp (option, "use-fallback-tls"))
3447 debug_options.use_fallback_tls = TRUE;
3448 else if (!strcmp (option, "debug-domain-unload"))
3449 mono_enable_debug_domain_unload (TRUE);
3450 else if (!strcmp (option, "partial-sharing"))
3451 mono_set_partial_sharing_supported (TRUE);
3452 else if (!strcmp (option, "align-small-structs"))
3453 mono_align_small_structs = TRUE;
3454 else if (!strcmp (option, "native-debugger-break"))
3455 debug_options.native_debugger_break = TRUE;
3456 else if (!strcmp (option, "disable_omit_fp"))
3457 debug_options.disable_omit_fp = TRUE;
3465 mini_parse_debug_options (void)
3467 char *options = g_getenv ("MONO_DEBUG");
3468 gchar **args, **ptr;
3473 args = g_strsplit (options, ",", -1);
3476 for (ptr = args; ptr && *ptr; ptr++) {
3477 const char *arg = *ptr;
3479 if (!mini_parse_debug_option (arg)) {
3480 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3481 fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
3490 mini_get_debug_options (void)
3492 return &debug_options;
3496 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3498 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3501 gpointer* desc = NULL;
3503 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3505 # if defined(__ppc64__) || defined(__powerpc64__)
3507 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3513 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3519 mini_get_addr_from_ftnptr (gpointer descr)
3521 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3522 return *(gpointer*)descr;
3529 register_jit_stats (void)
3531 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3532 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3533 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3534 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3535 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3536 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3537 mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
3538 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3539 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3540 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3541 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3542 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3543 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3544 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3545 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3546 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3547 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3548 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3549 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3550 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3551 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3552 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3553 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3554 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3555 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3556 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3557 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3558 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3559 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3560 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3561 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3562 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3563 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3564 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3565 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3566 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3567 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3568 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3569 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3570 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3571 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3572 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3573 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3574 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3575 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3576 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3577 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3578 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3579 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3580 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3581 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3582 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3583 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3584 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3585 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3586 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3587 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3588 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3589 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3590 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3591 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3594 static void runtime_invoke_info_free (gpointer value);
3597 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3599 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3600 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3602 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3606 class_method_pair_hash (gconstpointer data)
3608 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3610 return (gsize)pair->klass ^ (gsize)pair->method;
3614 mini_create_jit_domain_info (MonoDomain *domain)
3616 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3618 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3619 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3620 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3621 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3622 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3623 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3624 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3625 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3626 mono_jit_code_hash_init (&info->interp_code_hash);
3628 domain->runtime_info = info;
3632 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3634 MonoJumpList *jlist = (MonoJumpList *)value;
3635 g_slist_free (jlist->list);
3639 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3641 GSList *list = (GSList *)value;
3642 g_slist_free (list);
3646 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3648 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3649 mono_code_manager_destroy (di->code_mp);
3654 runtime_invoke_info_free (gpointer value)
3656 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3658 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3659 if (info->dyn_call_info)
3660 mono_arch_dyn_call_free (info->dyn_call_info);
3666 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3668 g_slist_free (value);
3672 mini_free_jit_domain_info (MonoDomain *domain)
3674 MonoJitDomainInfo *info = domain_jit_info (domain);
3676 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3677 g_hash_table_destroy (info->jump_target_hash);
3678 if (info->jump_target_got_slot_hash) {
3679 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3680 g_hash_table_destroy (info->jump_target_got_slot_hash);
3682 if (info->dynamic_code_hash) {
3683 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3684 g_hash_table_destroy (info->dynamic_code_hash);
3686 if (info->method_code_hash)
3687 g_hash_table_destroy (info->method_code_hash);
3688 g_hash_table_destroy (info->jump_trampoline_hash);
3689 g_hash_table_destroy (info->jit_trampoline_hash);
3690 g_hash_table_destroy (info->delegate_trampoline_hash);
3691 if (info->static_rgctx_trampoline_hash)
3692 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3693 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3694 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3695 g_hash_table_destroy (info->seq_points);
3696 g_hash_table_destroy (info->arch_seq_points);
3697 if (info->agent_info)
3698 mono_debugger_agent_free_domain_info (domain);
3699 if (info->gsharedvt_arg_tramp_hash)
3700 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3701 if (info->llvm_jit_callees) {
3702 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3703 g_hash_table_destroy (info->llvm_jit_callees);
3705 mono_internal_hash_table_destroy (&info->interp_code_hash);
3707 mono_llvm_free_domain_info (domain);
3710 g_free (domain->runtime_info);
3711 domain->runtime_info = NULL;
3714 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3717 code_manager_chunk_new (void *chunk, int size)
3719 mono_arch_code_chunk_new (chunk, size);
3723 code_manager_chunk_destroy (void *chunk)
3725 mono_arch_code_chunk_destroy (chunk);
3732 llvm_init_inner (void)
3734 if (!mono_llvm_load (NULL))
3745 * Load and initialize LLVM support.
3746 * Return TRUE on success.
3749 mini_llvm_init (void)
3752 static gboolean llvm_inited;
3753 static gboolean init_result;
3755 mono_loader_lock_if_inited ();
3757 init_result = llvm_init_inner ();
3760 mono_loader_unlock_if_inited ();
3768 mini_profiler_enable_with_options (const char* profile_options)
3770 mini_enable_profiler = TRUE;
3771 mini_profiler_options = g_strdup (profile_options);
3775 mini_init (const char *filename, const char *runtime_version)
3779 MonoRuntimeCallbacks callbacks;
3780 MonoThreadInfoRuntimeCallbacks ticallbacks;
3781 MonoCodeManagerCallbacks code_manager_callbacks;
3783 MONO_VES_INIT_BEGIN ();
3785 CHECKED_MONO_INIT ();
3787 #if defined(__linux__)
3788 if (access ("/proc/self/maps", F_OK) != 0) {
3789 g_print ("Mono requires /proc to be mounted.\n");
3794 #ifdef ENABLE_INTERPRETER
3795 mono_interp_init ();
3798 mono_os_mutex_init_recursive (&jit_mutex);
3800 mono_cross_helpers_run ();
3802 mono_counters_init ();
3806 mini_jit_init_job_control ();
3808 /* Happens when using the embedding interface */
3809 if (!default_opt_set)
3810 default_opt = mono_parse_default_optimizations (NULL);
3812 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3814 mono_set_generic_sharing_vt_supported (TRUE);
3817 mono_set_generic_sharing_vt_supported (TRUE);
3820 mono_tls_init_runtime_keys ();
3822 if (!global_codeman)
3823 global_codeman = mono_code_manager_new ();
3825 memset (&callbacks, 0, sizeof (callbacks));
3826 callbacks.create_ftnptr = mini_create_ftnptr;
3827 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3828 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3829 callbacks.set_cast_details = mono_set_cast_details;
3830 callbacks.debug_log = mono_debugger_agent_debug_log;
3831 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3832 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3833 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3834 callbacks.imt_entry_inited = mini_imt_entry_inited;
3835 callbacks.init_delegate = mini_init_delegate;
3836 #define JIT_INVOKE_WORKS
3837 #ifdef JIT_INVOKE_WORKS
3838 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3840 #define JIT_TRAMPOLINES_WORK
3841 #ifdef JIT_TRAMPOLINES_WORK
3842 callbacks.compile_method = mono_jit_compile_method;
3843 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3844 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3845 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3846 callbacks.free_method = mono_jit_free_method;
3847 #ifndef DISABLE_REMOTING
3848 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3852 mono_install_callbacks (&callbacks);
3854 memset (&ticallbacks, 0, sizeof (ticallbacks));
3855 ticallbacks.setup_async_callback = mono_setup_async_callback;
3856 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3857 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3858 ticallbacks.thread_state_init = mono_thread_state_init;
3861 mono_w32handle_init ();
3864 mono_thread_info_runtime_init (&ticallbacks);
3866 if (g_hasenv ("MONO_DEBUG")) {
3867 mini_parse_debug_options ();
3870 mono_code_manager_init ();
3872 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3873 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3874 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3875 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3877 mono_code_manager_install_callbacks (&code_manager_callbacks);
3881 mono_arch_cpu_init ();
3885 mono_unwind_init ();
3887 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3888 mono_lldb_init ("");
3889 mono_dont_free_domains = TRUE;
3892 #ifdef XDEBUG_ENABLED
3893 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3895 mono_xdebug_init (mono_xdebug);
3896 g_free (mono_xdebug);
3897 /* So methods for multiple domains don't have the same address */
3898 mono_dont_free_domains = TRUE;
3899 mono_using_xdebug = TRUE;
3900 } else if (mini_get_debug_options ()->gdb) {
3901 mono_xdebug_init ((char*)"gdb");
3902 mono_dont_free_domains = TRUE;
3903 mono_using_xdebug = TRUE;
3908 if (mono_use_llvm) {
3909 if (!mono_llvm_load (NULL)) {
3910 mono_use_llvm = FALSE;
3911 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3918 mono_trampolines_init ();
3920 if (default_opt & MONO_OPT_AOT)
3923 mono_debugger_agent_init ();
3925 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3926 mono_set_generic_sharing_supported (TRUE);
3929 mono_thread_info_signals_init ();
3931 #ifndef MONO_CROSS_COMPILE
3932 mono_runtime_install_handlers ();
3934 mono_threads_install_cleanup (mini_thread_cleanup);
3936 #ifdef JIT_TRAMPOLINES_WORK
3937 mono_install_create_domain_hook (mini_create_jit_domain_info);
3938 mono_install_free_domain_hook (mini_free_jit_domain_info);
3940 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3941 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3942 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3944 if (mini_profiler_enabled ()) {
3945 mono_profiler_load (mini_profiler_get_options ());
3946 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
3949 mono_profiler_started ();
3951 if (debug_options.collect_pagefault_stats)
3952 mono_aot_set_make_unreadable (TRUE);
3954 if (runtime_version)
3955 domain = mono_init_version (filename, runtime_version);
3957 domain = mono_init_from_assembly (filename, filename);
3959 if (mono_aot_only) {
3960 /* This helps catch code allocation requests */
3961 mono_code_manager_set_read_only (domain->code_mp);
3962 mono_marshal_use_aot_wrappers (TRUE);
3965 if (mono_llvm_only) {
3966 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3967 mono_set_always_build_imt_trampolines (TRUE);
3968 } else if (mono_aot_only) {
3969 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3971 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3974 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3975 mono_arch_finish_init ();
3979 /* This must come after mono_init () in the aot-only case */
3980 mono_exceptions_init ();
3982 /* This should come after mono_init () too */
3986 mono_create_helper_signatures ();
3989 register_jit_stats ();
3991 #define JIT_CALLS_WORK
3992 #ifdef JIT_CALLS_WORK
3993 /* Needs to be called here since register_jit_icall depends on it */
3994 mono_marshal_init ();
3996 mono_arch_register_lowlevel_calls ();
4000 mono_generic_sharing_init ();
4003 #ifdef MONO_ARCH_SIMD_INTRINSICS
4004 mono_simd_intrinsics_init ();
4007 mono_tasklets_init ();
4009 register_trampolines (domain);
4011 if (mono_compile_aot)
4013 * Avoid running managed code when AOT compiling, since the platform
4014 * might only support aot-only execution.
4016 mono_runtime_set_no_exec (TRUE);
4018 mono_mem_account_register_counters ();
4020 #define JIT_RUNTIME_WORKS
4021 #ifdef JIT_RUNTIME_WORKS
4022 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4023 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4024 mono_error_assert_ok (&error);
4025 mono_thread_attach (domain);
4028 if (mono_profiler_sampling_enabled ())
4029 mono_runtime_setup_stat_profiler ();
4031 MONO_PROFILER_RAISE (runtime_initialized, ());
4033 MONO_VES_INIT_END ();
4039 register_icalls (void)
4041 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4042 ves_icall_get_frame_info);
4043 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4044 ves_icall_get_trace);
4045 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4046 mono_runtime_install_handlers);
4047 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4048 mono_runtime_cleanup_handlers);
4050 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4051 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4052 mono_debugger_agent_unhandled_exception);
4056 * It's important that we pass `TRUE` as the last argument here, as
4057 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4058 * *did* emit a wrapper, we'd be looking at infinite recursion since
4059 * the wrapper would call the icall which would call the wrapper and
4062 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr", TRUE);
4063 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr", TRUE);
4065 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4066 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4067 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4068 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4069 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4070 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4072 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4073 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4074 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4075 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4076 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4077 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4078 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4079 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4080 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4082 // FIXME: This is broken
4083 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4086 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4087 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4088 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4089 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4090 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4091 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4093 if (mono_threads_is_coop_enabled ())
4094 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4096 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4097 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4098 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4099 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4100 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4101 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4103 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4104 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4105 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4108 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4109 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4110 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4111 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4114 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4115 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4116 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4117 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4118 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4121 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4122 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4125 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4126 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4127 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4130 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4131 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4134 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4135 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4136 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4137 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4138 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4139 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4140 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4143 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4144 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4145 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4148 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4149 register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);
4151 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4152 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4154 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4155 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4157 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4158 register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
4160 #ifdef MONO_ARCH_EMULATE_FREM
4161 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4162 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4165 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4166 if (mono_arch_is_soft_float ()) {
4167 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4168 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4169 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4170 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4171 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4172 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4173 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4174 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4175 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4176 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4177 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4178 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4180 #if SIZEOF_VOID_P == 4
4181 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4184 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4185 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4186 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4187 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4188 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4189 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4190 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4191 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4192 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4193 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4195 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4196 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4197 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4198 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4199 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4201 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4202 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4203 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4204 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4207 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4209 #ifdef COMPRESSED_INTERFACE_BITMAP
4210 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4213 #if SIZEOF_REGISTER == 4
4214 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4216 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4219 /* other jit icalls */
4220 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4221 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4222 "ptr ptr ptr", FALSE);
4223 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4224 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4225 "ptr ptr ptr ptr", FALSE);
4226 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4227 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4228 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4229 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4230 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4231 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4232 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4233 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4234 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4235 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4236 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4237 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4238 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4239 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4240 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4241 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4242 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4243 register_icall (mono_break, "mono_break", NULL, TRUE);
4244 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4245 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4246 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4247 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4248 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4249 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4250 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4251 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4252 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4253 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4254 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4256 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4257 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4259 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4260 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4261 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4262 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4263 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4265 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4267 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4268 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4269 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4270 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4272 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4273 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4274 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4275 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4276 /* This needs a wrapper so it can have a preserveall cconv */
4277 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4278 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4279 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4280 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4281 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4282 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4283 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4285 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4286 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4287 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4288 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4291 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4293 /* Register tls icalls */
4294 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4295 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4296 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4297 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4298 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4299 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4300 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4301 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4302 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4303 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4306 MonoJitStats mono_jit_stats = {0};
4309 print_jit_stats (void)
4311 if (mono_jit_stats.enabled) {
4312 g_print ("Mono Jit statistics\n");
4313 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4314 mono_jit_stats.max_ratio_method);
4315 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4316 mono_jit_stats.biggest_method);
4318 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4319 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4320 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4321 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4322 g_print ("Methods: %ld\n", mono_stats.method_count);
4323 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4324 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4325 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4327 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4328 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4329 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4331 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4332 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4333 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4334 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4336 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4337 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4338 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4339 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4340 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4341 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4342 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4343 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4345 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4346 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4347 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4349 g_free (mono_jit_stats.max_ratio_method);
4350 mono_jit_stats.max_ratio_method = NULL;
4351 g_free (mono_jit_stats.biggest_method);
4352 mono_jit_stats.biggest_method = NULL;
4357 mini_cleanup (MonoDomain *domain)
4359 if (mono_profiler_sampling_enabled ())
4360 mono_runtime_shutdown_stat_profiler ();
4363 cominterop_release_all_rcws ();
4366 #ifndef MONO_CROSS_COMPILE
4368 * mono_domain_finalize () needs to be called early since it needs the
4369 * execution engine still fully working (it may invoke managed finalizers).
4371 mono_domain_finalize (domain, 2000);
4374 /* This accesses metadata so needs to be called before runtime shutdown */
4377 #ifndef MONO_CROSS_COMPILE
4378 mono_runtime_cleanup (domain);
4381 mono_threadpool_cleanup ();
4383 MONO_PROFILER_RAISE (runtime_shutdown, ());
4385 mono_profiler_cleanup ();
4387 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4389 mono_icall_cleanup ();
4391 mono_runtime_cleanup_handlers ();
4393 #ifndef MONO_CROSS_COMPILE
4394 mono_domain_free (domain, TRUE);
4399 mono_llvm_cleanup ();
4402 mono_aot_cleanup ();
4404 mono_trampolines_cleanup ();
4406 mono_unwind_cleanup ();
4408 mono_code_manager_destroy (global_codeman);
4409 g_free (vtable_trampolines);
4411 mini_jit_cleanup ();
4413 mono_tramp_info_cleanup ();
4415 mono_arch_cleanup ();
4417 mono_generic_sharing_cleanup ();
4421 mono_trace_cleanup ();
4423 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4425 if (mono_inject_async_exc_method)
4426 mono_method_desc_free (mono_inject_async_exc_method);
4428 mono_tls_free_keys ();
4430 mono_os_mutex_destroy (&jit_mutex);
4432 mono_code_manager_cleanup ();
4435 mono_w32handle_cleanup ();
4440 mono_set_defaults (int verbose_level, guint32 opts)
4442 mini_verbose = verbose_level;
4443 mono_set_optimizations (opts);
4447 mono_disable_optimizations (guint32 opts)
4449 default_opt &= ~opts;
4453 mono_set_optimizations (guint32 opts)
4456 default_opt_set = TRUE;
4457 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4458 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4461 mono_set_generic_sharing_vt_supported (TRUE);
4466 mono_set_verbose_level (guint32 level)
4468 mini_verbose = level;
4472 * mono_get_runtime_build_info:
4473 * The returned string is owned by the caller. The returned string
4474 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4475 * \returns the runtime version + build date in string format.
4478 mono_get_runtime_build_info (void)
4480 if (mono_build_date)
4481 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4483 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4487 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4489 GHashTable *assemblies = (GHashTable*)user_data;
4490 MonoImage *image = mono_assembly_get_image (ass);
4491 MonoMethod *method, *invoke;
4494 if (g_hash_table_lookup (assemblies, ass))
4497 g_hash_table_insert (assemblies, ass, ass);
4499 if (mini_verbose > 0)
4500 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4502 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4505 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4507 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4510 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4512 if (method->is_generic || mono_class_is_gtd (method->klass))
4516 if (mini_verbose > 1) {
4517 char * desc = mono_method_full_name (method, TRUE);
4518 g_print ("Compiling %d %s\n", count, desc);
4521 mono_compile_method_checked (method, &error);
4522 if (!is_ok (&error)) {
4523 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4526 if (strcmp (method->name, "Finalize") == 0) {
4527 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4528 mono_compile_method_checked (invoke, &error);
4529 mono_error_assert_ok (&error);
4531 #ifndef DISABLE_REMOTING
4532 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4533 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4534 mono_compile_method_checked (invoke, &error);
4535 mono_error_assert_ok (&error);
4540 /* Load and precompile referenced assemblies as well */
4541 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4542 mono_assembly_load_reference (image, i);
4543 if (image->references [i])
4544 mono_precompile_assembly (image->references [i], assemblies);
4548 void mono_precompile_assemblies ()
4550 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4552 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4554 g_hash_table_destroy (assemblies);
4559 * Have to export this for AOT.
4562 mono_personality (void)
4565 g_assert_not_reached ();
4569 static MonoBreakPolicy
4570 always_insert_breakpoint (MonoMethod *method)
4572 return MONO_BREAK_POLICY_ALWAYS;
4575 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4578 * mono_set_break_policy:
4579 * \param policy_callback the new callback function
4581 * Allow embedders to decide whether to actually obey breakpoint instructions
4582 * (both break IL instructions and \c Debugger.Break method calls), for example
4583 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4584 * untrusted or semi-trusted code.
4586 * \p policy_callback will be called every time a break point instruction needs to
4587 * be inserted with the method argument being the method that calls \c Debugger.Break
4588 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4589 * if it wants the breakpoint to not be effective in the given method.
4590 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4593 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4595 if (policy_callback)
4596 break_policy_func = policy_callback;
4598 break_policy_func = always_insert_breakpoint;
4602 mini_should_insert_breakpoint (MonoMethod *method)
4604 switch (break_policy_func (method)) {
4605 case MONO_BREAK_POLICY_ALWAYS:
4607 case MONO_BREAK_POLICY_NEVER:
4609 case MONO_BREAK_POLICY_ON_DBG:
4610 g_warning ("mdb no longer supported");
4613 g_warning ("Incorrect value returned from break policy callback");
4618 // Custom handlers currently only implemented by Windows.
4621 mono_runtime_install_custom_handlers (const char *handlers)
4627 mono_runtime_install_custom_handlers_usage (void)
4630 "Custom Handlers:\n"
4631 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4632 " separated list of available handlers to install.\n"
4634 "No handlers supported on current platform.\n");
4636 #endif /* HOST_WIN32 */