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;
582 char *value = g_getenv ("COUNT");
584 int_val = atoi (value);
593 if (count == int_val)
603 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
608 gconstpointer trampoline;
609 MonoDomain *domain = mono_get_root_domain ();
610 gboolean check_exc = TRUE;
612 if (callinfo->wrapper)
613 return callinfo->wrapper;
615 if (callinfo->trampoline)
616 return callinfo->trampoline;
618 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
619 /* This icall is used to check for exceptions, so don't check in the wrapper */
622 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
623 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
627 trampoline = mono_compile_method_checked (wrapper, &error);
628 mono_error_assert_ok (&error);
631 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
632 mono_error_assert_ok (&error);
633 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
637 if (!callinfo->trampoline) {
638 mono_register_jit_icall_wrapper (callinfo, trampoline);
639 callinfo->trampoline = trampoline;
641 mono_loader_unlock ();
643 return callinfo->trampoline;
647 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
649 return mono_icall_get_wrapper_full (callinfo, FALSE);
652 static MonoJitDynamicMethodInfo*
653 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
655 MonoJitDynamicMethodInfo *res;
657 if (domain_jit_info (domain)->dynamic_code_hash)
658 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
665 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
668 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
670 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
672 g_assert (!sig->hasthis);
673 g_assert (sig->param_count < 3);
675 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
676 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
681 * For JIT icalls implemented in C.
682 * NAME should be the same as the name of the C function whose address is FUNC.
683 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
684 * can't throw exceptions.
687 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
689 MonoMethodSignature *sig;
692 sig = mono_create_icall_signature (sigstr);
696 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
700 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
702 MonoMethodSignature *sig;
705 sig = mono_create_icall_signature (sigstr);
709 mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
713 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
715 MonoMethodSignature *sig;
718 sig = mono_create_icall_signature (sigstr);
722 mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
726 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
728 MonoMethodSignature *sig;
731 sig = mono_create_icall_signature (sigstr);
735 mono_register_jit_icall (func, name, sig, save);
741 MonoJitTlsData *jit_tls;
743 if ((jit_tls = mono_tls_get_jit_tls ()))
746 * We do not assert here because this function can be called from
747 * mini-gc.c on a thread that has not executed any managed code, yet
748 * (the thread object allocation can trigger a collection).
754 mono_get_lmf_addr (void)
756 return (MonoLMF **)mono_tls_get_lmf_addr ();
760 mono_set_lmf (MonoLMF *lmf)
762 (*mono_get_lmf_addr ()) = lmf;
766 mono_get_jit_tls (void)
768 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
772 mono_set_jit_tls (MonoJitTlsData *jit_tls)
774 MonoThreadInfo *info;
776 mono_tls_set_jit_tls (jit_tls);
778 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
779 info = mono_thread_info_current ();
781 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
785 mono_set_lmf_addr (gpointer lmf_addr)
787 MonoThreadInfo *info;
789 mono_tls_set_lmf_addr (lmf_addr);
791 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
792 info = mono_thread_info_current ();
794 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
800 * Push an MonoLMFExt frame on the LMF stack.
803 mono_push_lmf (MonoLMFExt *ext)
805 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
808 lmf_addr = mono_get_lmf_addr ();
810 mono_arch_init_lmf_ext (ext, *lmf_addr);
812 mono_set_lmf ((MonoLMF*)ext);
821 * Pop the last frame from the LMF stack.
824 mono_pop_lmf (MonoLMF *lmf)
826 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
830 * mono_jit_thread_attach:
832 * Called by Xamarin.Mac and other products. Attach thread to runtime if
833 * needed and switch to @domain.
835 * @return the original domain which needs to be restored, or NULL.
838 mono_jit_thread_attach (MonoDomain *domain)
843 g_assert (!mono_threads_is_coop_enabled ());
846 /* Happens when called from AOTed code which is only used in the root domain. */
847 domain = mono_get_root_domain ();
852 attached = mono_tls_get_jit_tls () != NULL;
855 mono_thread_attach (domain);
858 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
861 orig = mono_domain_get ();
863 mono_domain_set (domain, TRUE);
865 return orig != domain ? orig : NULL;
869 * mono_jit_set_domain:
871 * Set domain to @domain if @domain is not null
874 mono_jit_set_domain (MonoDomain *domain)
876 g_assert (!mono_threads_is_coop_enabled ());
879 mono_domain_set (domain, TRUE);
884 * \param obj exception object
885 * Abort the thread, print exception information and stack trace
888 mono_thread_abort (MonoObject *obj)
890 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
892 /* handle_remove should be eventually called for this thread, too
895 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
896 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
899 mono_invoke_unhandled_exception_hook (obj);
904 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
906 MonoJitTlsData *jit_tls;
909 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
913 jit_tls = g_new0 (MonoJitTlsData, 1);
915 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
916 jit_tls->end_of_stack = stack_start;
918 mono_set_jit_tls (jit_tls);
920 lmf = g_new0 (MonoLMF, 1);
921 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
923 jit_tls->first_lmf = lmf;
925 mono_set_lmf_addr (&jit_tls->lmf);
929 #ifdef MONO_ARCH_HAVE_TLS_INIT
930 mono_arch_tls_init ();
933 mono_setup_altstack (jit_tls);
939 free_jit_tls_data (MonoJitTlsData *jit_tls)
941 mono_arch_free_jit_tls_data (jit_tls);
942 mono_free_altstack (jit_tls);
944 g_free (jit_tls->first_lmf);
949 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
951 MonoThreadInfo *thread;
952 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
953 thread = mono_thread_info_current_unchecked ();
955 thread->jit_data = jit_tls;
957 mono_arch_cpu_init ();
960 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
963 mono_thread_abort_dummy (MonoObject *obj)
965 if (mono_thread_attach_aborted_cb)
966 mono_thread_attach_aborted_cb (obj);
968 mono_thread_abort (obj);
972 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
974 MonoThreadInfo *thread;
975 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
976 thread = mono_thread_info_current_unchecked ();
978 thread->jit_data = jit_tls;
980 mono_arch_cpu_init ();
984 mini_thread_cleanup (MonoNativeThreadId tid)
986 MonoJitTlsData *jit_tls = NULL;
987 MonoThreadInfo *info;
989 info = mono_thread_info_current_unchecked ();
991 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
992 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
993 * not a trivial thing.
995 * The current offender is mono_thread_manage which cleanup threads from the outside.
997 if (info && mono_thread_info_get_tid (info) == tid) {
998 jit_tls = (MonoJitTlsData *)info->jit_data;
999 info->jit_data = NULL;
1001 mono_set_jit_tls (NULL);
1003 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1004 if (mono_get_lmf ()) {
1005 mono_set_lmf (NULL);
1006 mono_set_lmf_addr (NULL);
1009 info = mono_thread_info_lookup (tid);
1011 jit_tls = (MonoJitTlsData *)info->jit_data;
1012 info->jit_data = NULL;
1014 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1018 free_jit_tls_data (jit_tls);
1022 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1024 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1028 ji->data.target = target;
1034 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1036 static const char* const patch_info_str[] = {
1037 #define PATCH_INFO(a,b) "" #a,
1038 #include "patch-info.h"
1043 mono_ji_type_to_string (MonoJumpInfoType type)
1045 return patch_info_str [type];
1049 mono_print_ji (const MonoJumpInfo *ji)
1052 case MONO_PATCH_INFO_RGCTX_FETCH: {
1053 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1055 printf ("[RGCTX_FETCH ");
1056 mono_print_ji (entry->data);
1057 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1060 case MONO_PATCH_INFO_METHODCONST: {
1061 char *s = mono_method_full_name (ji->data.method, TRUE);
1062 printf ("[METHODCONST - %s]", s);
1066 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1067 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1071 printf ("[%s]", patch_info_str [ji->type]);
1079 mono_ji_type_to_string (MonoJumpInfoType type)
1085 mono_print_ji (const MonoJumpInfo *ji)
1092 * mono_patch_info_dup_mp:
1094 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1097 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1099 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1100 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1102 switch (patch_info->type) {
1103 case MONO_PATCH_INFO_RVA:
1104 case MONO_PATCH_INFO_LDSTR:
1105 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1106 case MONO_PATCH_INFO_LDTOKEN:
1107 case MONO_PATCH_INFO_DECLSEC:
1108 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1109 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1111 case MONO_PATCH_INFO_SWITCH:
1112 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1113 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1114 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1115 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1117 case MONO_PATCH_INFO_RGCTX_FETCH:
1118 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1119 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1120 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1121 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1123 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1124 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1125 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1127 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1128 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1129 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1131 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1132 MonoGSharedVtMethodInfo *info;
1133 MonoGSharedVtMethodInfo *oinfo;
1136 oinfo = patch_info->data.gsharedvt_method;
1137 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1138 res->data.gsharedvt_method = info;
1139 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1140 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1141 for (i = 0; i < oinfo->num_entries; ++i) {
1142 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1143 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1145 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1147 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1148 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1151 case MONO_PATCH_INFO_VIRT_METHOD: {
1152 MonoJumpInfoVirtMethod *info;
1153 MonoJumpInfoVirtMethod *oinfo;
1155 oinfo = patch_info->data.virt_method;
1156 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1157 res->data.virt_method = info;
1158 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1169 mono_patch_info_hash (gconstpointer data)
1171 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1174 case MONO_PATCH_INFO_RVA:
1175 case MONO_PATCH_INFO_LDSTR:
1176 case MONO_PATCH_INFO_LDTOKEN:
1177 case MONO_PATCH_INFO_DECLSEC:
1178 return (ji->type << 8) | ji->data.token->token;
1179 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1180 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1181 case MONO_PATCH_INFO_INTERNAL_METHOD:
1182 return (ji->type << 8) | g_str_hash (ji->data.name);
1183 case MONO_PATCH_INFO_VTABLE:
1184 case MONO_PATCH_INFO_CLASS:
1185 case MONO_PATCH_INFO_IID:
1186 case MONO_PATCH_INFO_ADJUSTED_IID:
1187 case MONO_PATCH_INFO_METHODCONST:
1188 case MONO_PATCH_INFO_METHOD:
1189 case MONO_PATCH_INFO_METHOD_JUMP:
1190 case MONO_PATCH_INFO_IMAGE:
1191 case MONO_PATCH_INFO_ICALL_ADDR:
1192 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1193 case MONO_PATCH_INFO_FIELD:
1194 case MONO_PATCH_INFO_SFLDA:
1195 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1196 case MONO_PATCH_INFO_METHOD_RGCTX:
1197 case MONO_PATCH_INFO_SIGNATURE:
1198 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1199 case MONO_PATCH_INFO_AOT_JIT_INFO:
1200 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1201 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1202 return (ji->type << 8) | (gssize)ji->data.target;
1203 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1204 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1205 case MONO_PATCH_INFO_RGCTX_FETCH:
1206 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1207 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1209 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1211 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1212 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1213 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1214 case MONO_PATCH_INFO_GC_NURSERY_START:
1215 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1216 case MONO_PATCH_INFO_GOT_OFFSET:
1217 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1218 case MONO_PATCH_INFO_AOT_MODULE:
1219 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1220 return (ji->type << 8);
1221 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1222 return (ji->type << 8) | (ji->data.index);
1223 case MONO_PATCH_INFO_SWITCH:
1224 return (ji->type << 8) | ji->data.table->table_size;
1225 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1226 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1227 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1228 /* Hash on the selector name */
1229 return g_str_hash (ji->data.target);
1230 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1231 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1232 case MONO_PATCH_INFO_LDSTR_LIT:
1233 return g_str_hash (ji->data.target);
1234 case MONO_PATCH_INFO_VIRT_METHOD: {
1235 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1237 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1239 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1240 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1241 return (ji->type << 8) | g_str_hash (ji->data.target);
1242 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1243 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1245 printf ("info type: %d\n", ji->type);
1246 mono_print_ji (ji); printf ("\n");
1247 g_assert_not_reached ();
1253 * mono_patch_info_equal:
1255 * This might fail to recognize equivalent patches, i.e. floats, so its only
1256 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1260 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1262 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1263 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1265 if (ji1->type != ji2->type)
1268 switch (ji1->type) {
1269 case MONO_PATCH_INFO_RVA:
1270 case MONO_PATCH_INFO_LDSTR:
1271 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1272 case MONO_PATCH_INFO_LDTOKEN:
1273 case MONO_PATCH_INFO_DECLSEC:
1274 if ((ji1->data.token->image != ji2->data.token->image) ||
1275 (ji1->data.token->token != ji2->data.token->token) ||
1276 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1277 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1278 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1281 case MONO_PATCH_INFO_INTERNAL_METHOD:
1282 return g_str_equal (ji1->data.name, ji2->data.name);
1283 case MONO_PATCH_INFO_RGCTX_FETCH:
1284 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1285 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1286 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1288 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);
1290 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1291 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1292 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1294 return c1->sig == c2->sig && c1->method == c2->method;
1296 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1297 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1298 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1299 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;
1300 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1301 return ji1->data.index == ji2->data.index;
1302 case MONO_PATCH_INFO_VIRT_METHOD:
1303 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1304 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1305 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1306 if (ji1->data.target == ji2->data.target)
1308 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1309 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1310 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1312 if (ji1->data.target != ji2->data.target)
1321 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1323 unsigned char *ip = patch_info->ip.i + code;
1324 gconstpointer target = NULL;
1328 switch (patch_info->type) {
1329 case MONO_PATCH_INFO_BB:
1331 * FIXME: This could be hit for methods without a prolog. Should use -1
1332 * but too much code depends on a 0 initial value.
1334 //g_assert (patch_info->data.bb->native_offset);
1335 target = patch_info->data.bb->native_offset + code;
1337 case MONO_PATCH_INFO_ABS:
1338 target = patch_info->data.target;
1340 case MONO_PATCH_INFO_LABEL:
1341 target = patch_info->data.inst->inst_c0 + code;
1343 case MONO_PATCH_INFO_IP:
1346 case MONO_PATCH_INFO_METHOD_REL:
1347 target = code + patch_info->data.offset;
1349 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1350 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1352 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1353 g_assert_not_reached ();
1355 target = mono_icall_get_wrapper (mi);
1358 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1359 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1360 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1362 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1363 g_assert_not_reached ();
1368 case MONO_PATCH_INFO_METHOD_JUMP:
1369 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1370 if (!mono_error_ok (error))
1373 case MONO_PATCH_INFO_METHOD:
1374 if (patch_info->data.method == method) {
1377 /* get the trampoline to the method from the domain */
1378 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1379 if (!mono_error_ok (error))
1383 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1386 mono_domain_lock (domain);
1387 if (!domain_jit_info (domain)->method_code_hash)
1388 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1389 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1391 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1392 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1394 mono_domain_unlock (domain);
1398 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1399 g_assert (mono_threads_is_coop_enabled ());
1400 target = (gpointer)&mono_polling_required;
1402 case MONO_PATCH_INFO_SWITCH: {
1403 gpointer *jump_table;
1405 if (method && method->dynamic) {
1406 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1408 if (mono_aot_only) {
1409 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1411 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1415 for (i = 0; i < patch_info->data.table->table_size; i++) {
1416 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1419 target = jump_table;
1422 case MONO_PATCH_INFO_METHODCONST:
1423 case MONO_PATCH_INFO_CLASS:
1424 case MONO_PATCH_INFO_IMAGE:
1425 case MONO_PATCH_INFO_FIELD:
1426 case MONO_PATCH_INFO_SIGNATURE:
1427 case MONO_PATCH_INFO_AOT_MODULE:
1428 target = patch_info->data.target;
1430 case MONO_PATCH_INFO_IID:
1431 mono_class_init (patch_info->data.klass);
1432 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1434 case MONO_PATCH_INFO_ADJUSTED_IID:
1435 mono_class_init (patch_info->data.klass);
1436 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1438 case MONO_PATCH_INFO_VTABLE:
1439 target = mono_class_vtable (domain, patch_info->data.klass);
1442 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1443 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1445 if (del_tramp->is_virtual)
1446 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1448 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1451 case MONO_PATCH_INFO_SFLDA: {
1452 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1454 if (mono_class_field_is_special_static (patch_info->data.field)) {
1455 gpointer addr = NULL;
1457 mono_domain_lock (domain);
1458 if (domain->special_static_fields)
1459 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1460 mono_domain_unlock (domain);
1466 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1467 /* Done by the generated code */
1471 if (!mono_runtime_class_init_full (vtable, error)) {
1476 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1479 case MONO_PATCH_INFO_RVA: {
1480 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1483 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1484 target = mono_image_rva_map (patch_info->data.token->image, rva);
1487 case MONO_PATCH_INFO_R4:
1488 case MONO_PATCH_INFO_R8:
1489 target = patch_info->data.target;
1491 case MONO_PATCH_INFO_EXC_NAME:
1492 target = patch_info->data.name;
1494 case MONO_PATCH_INFO_LDSTR:
1496 mono_ldstr_checked (domain, patch_info->data.token->image,
1497 mono_metadata_token_index (patch_info->data.token->token), error);
1499 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1501 MonoClass *handle_class;
1503 handle = mono_ldtoken_checked (patch_info->data.token->image,
1504 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1505 if (!mono_error_ok (error))
1507 mono_class_init (handle_class);
1508 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1510 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1511 if (!mono_error_ok (error))
1515 case MONO_PATCH_INFO_LDTOKEN: {
1517 MonoClass *handle_class;
1519 handle = mono_ldtoken_checked (patch_info->data.token->image,
1520 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1521 if (!mono_error_ok (error))
1522 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1523 mono_class_init (handle_class);
1528 case MONO_PATCH_INFO_DECLSEC:
1529 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1531 case MONO_PATCH_INFO_ICALL_ADDR:
1532 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1533 /* run_cctors == 0 -> AOT */
1534 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1535 const char *exc_class;
1536 const char *exc_arg;
1539 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1541 if (mono_aot_only) {
1542 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1545 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));
1551 target = mono_lookup_internal_call (patch_info->data.method);
1553 if (!target && run_cctors)
1554 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1557 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1558 target = mono_thread_interruption_request_flag ();
1560 case MONO_PATCH_INFO_METHOD_RGCTX: {
1561 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1564 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1567 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1568 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1570 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1573 case MONO_PATCH_INFO_BB_OVF:
1574 case MONO_PATCH_INFO_EXC_OVF:
1575 case MONO_PATCH_INFO_GOT_OFFSET:
1576 case MONO_PATCH_INFO_NONE:
1578 case MONO_PATCH_INFO_RGCTX_FETCH: {
1579 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1581 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1584 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1585 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1587 /* AOT, not needed */
1590 target = mono_arch_get_seq_point_info (domain, code);
1593 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1594 int card_table_shift_bits;
1595 gpointer card_table_mask;
1597 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1600 case MONO_PATCH_INFO_GC_NURSERY_START: {
1604 target = mono_gc_get_nursery (&shift_bits, &size);
1607 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1611 mono_gc_get_nursery (&shift_bits, &size);
1613 target = (gpointer)(mgreg_t)shift_bits;
1616 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1617 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1620 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1624 case MONO_PATCH_INFO_LDSTR_LIT: {
1628 len = strlen ((const char *)patch_info->data.target);
1629 s = (char *)mono_domain_alloc0 (domain, len + 1);
1630 memcpy (s, patch_info->data.target, len);
1635 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1636 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1638 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1639 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1641 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1642 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1644 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1645 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1651 g_assert_not_reached ();
1654 return (gpointer)target;
1658 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1660 MonoGenericInst *inst;
1663 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1665 if (context && context->class_inst) {
1666 inst = context->class_inst;
1667 for (i = 0; i < inst->type_argc; ++i) {
1668 MonoType *type = inst->type_argv [i];
1670 if (mini_is_gsharedvt_gparam (type))
1671 gsctx->is_gsharedvt = TRUE;
1674 if (context && context->method_inst) {
1675 inst = context->method_inst;
1677 for (i = 0; i < inst->type_argc; ++i) {
1678 MonoType *type = inst->type_argv [i];
1680 if (mini_is_gsharedvt_gparam (type))
1681 gsctx->is_gsharedvt = TRUE;
1687 * LOCKING: Acquires the jit code hash lock.
1690 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1693 static gboolean inited = FALSE;
1694 static int lookups = 0;
1695 static int failed_lookups = 0;
1697 mono_domain_jit_code_hash_lock (domain);
1698 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1699 if (!ji && shared) {
1700 /* Try generic sharing */
1701 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1702 if (ji && !ji->has_generic_jit_info)
1705 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1706 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1714 mono_domain_jit_code_hash_unlock (domain);
1720 lookup_method (MonoDomain *domain, MonoMethod *method)
1725 ji = mini_lookup_method (domain, method, NULL);
1728 if (!mono_method_is_generic_sharable (method, FALSE))
1730 shared = mini_get_shared_method (method);
1731 ji = mini_lookup_method (domain, method, shared);
1738 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1740 return lookup_method (domain, method);
1744 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1749 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1750 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1752 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
1753 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1756 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
1757 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1760 mono_class_init (klass);
1765 static FILE* perf_map_file;
1768 mono_enable_jit_map (void)
1770 if (!perf_map_file) {
1772 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1774 perf_map_file = fopen (name, "w");
1779 mono_emit_jit_tramp (void *start, int size, const char *desc)
1782 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1786 mono_emit_jit_map (MonoJitInfo *jinfo)
1788 if (perf_map_file) {
1789 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1790 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1796 mono_jit_map_is_enabled (void)
1798 return perf_map_file != NULL;
1804 no_gsharedvt_in_wrapper (void)
1806 g_assert_not_reached ();
1812 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.
1813 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1814 Dependency management in this case is too complex to justify implementing it.
1816 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1819 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1820 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1821 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1822 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1827 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1828 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1829 int threads_waiting; /* Number of threads waiting on this job */
1830 gboolean has_cond; /* True if @cond was initialized */
1831 gboolean done; /* True if the method finished JIT'ing */
1832 MonoCoopCond cond; /* Cond sleeping threads wait one */
1833 } JitCompilationEntry;
1836 GPtrArray *in_flight_methods; //JitCompilationEntry*
1838 } JitCompilationData;
1840 static JitCompilationData compilation_data;
1841 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1844 mini_jit_init_job_control (void)
1846 mono_coop_mutex_init (&compilation_data.lock);
1847 compilation_data.in_flight_methods = g_ptr_array_new ();
1851 lock_compilation_data (void)
1853 mono_coop_mutex_lock (&compilation_data.lock);
1857 unlock_compilation_data (void)
1859 mono_coop_mutex_unlock (&compilation_data.lock);
1862 static JitCompilationEntry*
1863 find_method (MonoMethod *method, MonoDomain *domain)
1866 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1867 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1868 if (e->method == method && e->domain == domain)
1876 add_current_thread (MonoJitTlsData *jit_tls)
1878 ++jit_tls->active_jit_methods;
1882 unref_jit_entry (JitCompilationEntry *entry)
1885 if (entry->ref_count)
1887 if (entry->has_cond)
1888 mono_coop_cond_destroy (&entry->cond);
1893 * Returns true if this method waited successfully for another thread to JIT it
1896 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1898 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1899 JitCompilationEntry *entry;
1901 static gboolean inited;
1903 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1904 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1905 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1906 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1910 lock_compilation_data ();
1912 if (!(entry = find_method (method, domain))) {
1913 entry = g_new0 (JitCompilationEntry, 1);
1914 entry->method = method;
1915 entry->domain = domain;
1916 entry->compilation_count = entry->ref_count = 1;
1917 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1918 g_assert (find_method (method, domain) == entry);
1919 add_current_thread (jit_tls);
1921 unlock_compilation_data ();
1923 } else if (jit_tls->active_jit_methods > 0) {
1924 //We can't suspend the current thread if it's already JITing a method.
1925 //Dependency management is too compilated and we want to get rid of this anyways.
1926 ++entry->compilation_count;
1927 ++jit_methods_multiple;
1928 ++jit_tls->active_jit_methods;
1930 unlock_compilation_data ();
1933 ++jit_methods_waited;
1936 if (!entry->has_cond) {
1937 mono_coop_cond_init (&entry->cond);
1938 entry->has_cond = TRUE;
1942 ++entry->threads_waiting;
1944 g_assert (entry->has_cond);
1945 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1946 --entry->threads_waiting;
1949 unref_jit_entry (entry);
1950 unlock_compilation_data ();
1953 ++jit_spurious_wakeups;
1960 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1962 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1964 lock_compilation_data ();
1966 g_assert (jit_tls->active_jit_methods > 0);
1967 --jit_tls->active_jit_methods;
1969 JitCompilationEntry *entry = find_method (method, target_domain);
1970 g_assert (entry); // It would be weird to fail
1973 if (entry->threads_waiting) {
1974 g_assert (entry->has_cond);
1975 mono_coop_cond_broadcast (&entry->cond);
1978 if (--entry->compilation_count == 0) {
1979 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1980 unref_jit_entry (entry);
1983 unlock_compilation_data ();
1988 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1990 MonoDomain *target_domain, *domain = mono_domain_get ();
1992 gpointer code = NULL, p;
1994 MonoJitICallInfo *callinfo = NULL;
1995 WrapperInfo *winfo = NULL;
1999 #ifdef ENABLE_INTERPRETER
2000 if (mono_use_interpreter && !jit_only) {
2001 code = mono_interp_create_method_pointer (method, error);
2008 /* Should be handled by the caller */
2009 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2012 * ICALL wrappers are handled specially, since there is only one copy of them
2013 * shared by all appdomains.
2015 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2016 winfo = mono_marshal_get_wrapper_info (method);
2017 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2018 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2019 g_assert (callinfo);
2021 /* Must be domain neutral since there is only one copy */
2022 opt |= MONO_OPT_SHARED;
2024 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2025 opt &= ~MONO_OPT_SHARED;
2028 if (opt & MONO_OPT_SHARED)
2029 target_domain = mono_get_root_domain ();
2031 target_domain = domain;
2033 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2034 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2037 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2038 MonoGenericContext *ctx = NULL;
2039 if (method->is_inflated)
2040 ctx = mono_method_get_context (method);
2041 method = info->d.synchronized_inner.method;
2043 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2044 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2050 info = lookup_method (target_domain, method);
2052 /* We can't use a domain specific method in another domain */
2053 if (! ((domain != target_domain) && !info->domain_neutral)) {
2056 mono_jit_stats.methods_lookups++;
2057 vtable = mono_class_vtable_full (domain, method->klass, error);
2061 if (!mono_runtime_class_init_full (vtable, error))
2063 return mono_create_ftnptr (target_domain, info->code_start);
2067 #ifdef MONO_USE_AOT_COMPILER
2068 if (opt & MONO_OPT_AOT) {
2069 MonoDomain *domain = NULL;
2071 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2072 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2074 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
2075 /* AOT'd wrappers for interp must be owned by root domain */
2076 domain = mono_get_root_domain ();
2080 domain = mono_domain_get ();
2082 mono_class_init (method->klass);
2084 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2087 if (mono_gc_is_critical_method (method)) {
2089 * The suspend code needs to be able to lookup these methods by ip in async context,
2090 * so preload their jit info.
2092 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2097 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2098 * This is not a problem, since it will be initialized when the method is first
2099 * called by init_method ().
2101 if (!mono_llvm_only) {
2102 vtable = mono_class_vtable (domain, method->klass);
2104 if (!mono_runtime_class_init_full (vtable, error))
2113 if (!code && mono_llvm_only) {
2114 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2115 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2117 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2119 * These wrappers are only created for signatures which are in the program, but
2120 * sometimes we load methods too eagerly and have to create them even if they
2121 * will never be called.
2123 return no_gsharedvt_in_wrapper;
2129 if (wait_or_register_method_to_compile (method, target_domain))
2131 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2132 unregister_method_for_compile (method, target_domain);
2134 if (!mono_error_ok (error))
2137 if (!code && mono_llvm_only) {
2138 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2139 g_assert_not_reached ();
2145 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2149 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2151 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2155 p = mono_create_ftnptr (target_domain, code);
2158 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2159 mono_loader_lock ();
2161 if (!callinfo->wrapper) {
2162 callinfo->wrapper = p;
2163 mono_register_jit_icall_wrapper (callinfo, p);
2166 mono_loader_unlock ();
2173 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2177 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2182 * mono_jit_compile_method_jit_only:
2184 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2187 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2191 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2195 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2197 invalidated_delegate_trampoline (char *desc)
2199 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2200 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2206 * mono_jit_free_method:
2208 * Free all memory allocated by the JIT for METHOD.
2211 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2213 MonoJitDynamicMethodInfo *ji;
2214 gboolean destroy = TRUE;
2215 GHashTableIter iter;
2216 MonoJumpList *jlist;
2218 g_assert (method->dynamic);
2220 mono_domain_lock (domain);
2221 ji = mono_dynamic_code_hash_lookup (domain, method);
2222 mono_domain_unlock (domain);
2227 mono_debug_remove_method (method, domain);
2228 mono_lldb_remove_method (domain, method, ji);
2230 mono_domain_lock (domain);
2231 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2232 mono_domain_jit_code_hash_lock (domain);
2233 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2234 mono_domain_jit_code_hash_unlock (domain);
2235 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2237 /* requires the domain lock - took above */
2238 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2240 /* Remove jump targets in this method */
2241 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2242 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2243 GSList *tmp, *remove;
2246 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2247 guint8 *ip = (guint8 *)tmp->data;
2249 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2250 remove = g_slist_prepend (remove, tmp);
2252 for (tmp = remove; tmp; tmp = tmp->next) {
2253 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2255 g_slist_free (remove);
2257 mono_domain_unlock (domain);
2259 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2260 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2262 * Instead of freeing the code, change it to call an error routine
2263 * so people can fix their code.
2265 char *type = mono_type_full_name (&method->klass->byval_arg);
2266 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2269 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2275 * This needs to be done before freeing code_mp, since the code address is the
2276 * key in the table, so if we free the code_mp first, another thread can grab the
2277 * same code address and replace our entry in the table.
2279 mono_jit_info_table_remove (domain, ji->ji);
2282 mono_code_manager_destroy (ji->code_mp);
2287 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2289 MonoDomain *target_domain;
2292 if (default_opt & MONO_OPT_SHARED)
2293 target_domain = mono_get_root_domain ();
2295 target_domain = domain;
2297 info = lookup_method (target_domain, method);
2299 /* We can't use a domain specific method in another domain */
2300 if (! ((domain != target_domain) && !info->domain_neutral)) {
2301 mono_jit_stats.methods_lookups++;
2304 return info->code_start;
2313 static guint32 bisect_opt = 0;
2314 static GHashTable *bisect_methods_hash = NULL;
2317 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2320 char method_name [2048];
2323 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2324 g_assert (bisect_methods_hash);
2326 file = fopen (method_list_filename, "r");
2329 while (fgets (method_name, sizeof (method_name), file)) {
2330 size_t len = strlen (method_name);
2332 g_assert (method_name [len - 1] == '\n');
2333 method_name [len - 1] = 0;
2334 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2336 g_assert (feof (file));
2339 gboolean mono_do_single_method_regression = FALSE;
2340 guint32 mono_single_method_regression_opt = 0;
2341 MonoMethod *mono_current_single_method;
2342 GSList *mono_single_method_list;
2343 GHashTable *mono_single_method_hash;
2346 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2350 if (bisect_methods_hash) {
2351 char *name = mono_method_full_name (method, TRUE);
2352 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2355 return default_opt | bisect_opt;
2357 if (!mono_do_single_method_regression)
2359 if (!mono_current_single_method) {
2360 if (!mono_single_method_hash)
2361 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2362 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2363 g_hash_table_insert (mono_single_method_hash, method, method);
2364 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2368 if (method == mono_current_single_method)
2369 return mono_single_method_regression_opt;
2374 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2376 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2381 gpointer compiled_method;
2382 gpointer runtime_invoke;
2384 MonoDynCallInfo *dyn_call_info;
2385 MonoClass *ret_box_class;
2386 MonoMethodSignature *sig;
2387 gboolean gsharedvt_invoke;
2388 gpointer *wrapper_arg;
2389 } RuntimeInvokeInfo;
2391 static RuntimeInvokeInfo*
2392 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2395 RuntimeInvokeInfo *info;
2397 info = g_new0 (RuntimeInvokeInfo, 1);
2398 info->compiled_method = compiled_method;
2399 if (mono_llvm_only && method->string_ctor)
2400 info->sig = mono_marshal_get_string_ctor_signature (method);
2402 info->sig = mono_method_signature (method);
2404 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2405 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2406 if (!mono_error_ok (error))
2408 g_assert (info->vtable);
2410 MonoMethodSignature *sig = info->sig;
2414 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2415 * in full-aot mode, so we use a slower, but more generic wrapper if
2416 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2418 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2419 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2420 gboolean supported = TRUE;
2423 if (method->string_ctor)
2424 sig = mono_marshal_get_string_ctor_signature (method);
2426 for (i = 0; i < sig->param_count; ++i) {
2427 MonoType *t = sig->params [i];
2429 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2433 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2437 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2441 ret_type = sig->ret;
2442 switch (ret_type->type) {
2443 case MONO_TYPE_VOID:
2455 case MONO_TYPE_BOOLEAN:
2456 case MONO_TYPE_CHAR:
2459 info->ret_box_class = mono_class_from_mono_type (ret_type);
2462 info->ret_box_class = mono_defaults.int_class;
2464 case MONO_TYPE_STRING:
2465 case MONO_TYPE_CLASS:
2466 case MONO_TYPE_ARRAY:
2467 case MONO_TYPE_SZARRAY:
2468 case MONO_TYPE_OBJECT:
2470 case MONO_TYPE_GENERICINST:
2471 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2472 info->ret_box_class = mono_class_from_mono_type (ret_type);
2474 case MONO_TYPE_VALUETYPE:
2475 info->ret_box_class = mono_class_from_mono_type (ret_type);
2478 g_assert_not_reached ();
2482 if (!info->dyn_call_info) {
2483 if (mono_llvm_only) {
2484 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2485 g_assert_not_reached ();
2487 info->gsharedvt_invoke = TRUE;
2488 if (!callee_gsharedvt) {
2489 /* Invoke a gsharedvt out wrapper instead */
2490 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2491 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2493 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2494 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2496 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2497 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2498 g_free (wrapper_sig);
2500 info->compiled_method = mono_jit_compile_method (wrapper, error);
2501 if (!mono_error_ok (error)) {
2506 /* Gsharedvt methods can be invoked the same way */
2507 /* The out wrapper has the same signature as the compiled gsharedvt method */
2508 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2510 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2512 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2513 g_free (wrapper_sig);
2516 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2517 if (!mono_error_ok (error)) {
2527 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2529 MonoMethodSignature *sig = info->sig;
2530 MonoDomain *domain = mono_domain_get ();
2531 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2533 gpointer retval_ptr;
2534 guint8 retval [256];
2535 gpointer *param_refs;
2540 g_assert (info->gsharedvt_invoke);
2543 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2544 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2545 * signatures, so we only have to generate runtime invoke wrappers for these
2547 * This code also handles invocation of gsharedvt methods directly, no
2548 * out wrappers are used in that case.
2550 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2551 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2554 * The runtime invoke wrappers expects pointers to primitive types, so have to
2558 args [pindex ++] = &obj;
2559 if (sig->ret->type != MONO_TYPE_VOID) {
2560 retval_ptr = (gpointer)&retval;
2561 args [pindex ++] = &retval_ptr;
2563 for (i = 0; i < sig->param_count; ++i) {
2564 MonoType *t = sig->params [i];
2566 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2567 MonoClass *klass = mono_class_from_mono_type (t);
2568 guint8 *nullable_buf;
2571 size = mono_class_value_size (klass, NULL);
2572 nullable_buf = g_alloca (size);
2573 g_assert (nullable_buf);
2575 /* The argument pointed to by params [i] is either a boxed vtype or null */
2576 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2577 params [i] = nullable_buf;
2580 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2581 param_refs [i] = params [i];
2582 params [i] = &(param_refs [i]);
2584 args [pindex ++] = ¶ms [i];
2586 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2587 args [pindex ++] = &info->wrapper_arg;
2589 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2591 runtime_invoke (NULL, args, exc, info->compiled_method);
2595 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2596 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2598 return *(MonoObject**)retval;
2602 * mono_jit_runtime_invoke:
2603 * \param method: the method to invoke
2604 * \param obj: this pointer
2605 * \param params: array of parameter values.
2606 * \param exc: Set to the exception raised in the managed method.
2607 * \param error: error or caught exception object
2608 * If \p exc is NULL, \p error is thrown instead.
2609 * If coop is enabled, \p exc argument is ignored -
2610 * all exceptions are caught and propagated through \p error
2613 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2615 MonoMethod *invoke, *callee;
2616 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2617 MonoDomain *domain = mono_domain_get ();
2618 MonoJitDomainInfo *domain_info;
2619 RuntimeInvokeInfo *info, *info2;
2620 MonoJitInfo *ji = NULL;
2621 gboolean callee_gsharedvt = FALSE;
2623 #ifdef ENABLE_INTERPRETER
2624 if (mono_use_interpreter)
2625 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2630 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2631 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2635 domain_info = domain_jit_info (domain);
2637 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2640 if (mono_security_core_clr_enabled ()) {
2642 * This might be redundant since mono_class_vtable () already does this,
2643 * but keep it just in case for moonlight.
2645 mono_class_setup_vtable (method->klass);
2646 if (mono_class_has_failure (method->klass)) {
2647 mono_error_set_for_class_failure (error, method->klass);
2649 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2654 gpointer compiled_method;
2657 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2658 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2660 * Array Get/Set/Address methods. The JIT implements them using inline code
2661 * inside the runtime invoke wrappers, so no need to compile them.
2663 if (mono_aot_only) {
2665 * Call a wrapper, since the runtime invoke wrapper was not generated.
2667 MonoMethod *wrapper;
2669 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2670 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2678 compiled_method = mono_jit_compile_method (callee, error);
2679 if (!compiled_method) {
2680 g_assert (!mono_error_ok (error));
2684 if (mono_llvm_only) {
2685 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2686 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2687 if (callee_gsharedvt)
2688 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2691 if (!callee_gsharedvt)
2692 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2694 compiled_method = NULL;
2697 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2698 if (!mono_error_ok (error))
2701 mono_domain_lock (domain);
2702 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2703 mono_domain_unlock (domain);
2711 * We need this here because mono_marshal_get_runtime_invoke can place
2712 * the helper method in System.Object and not the target class.
2714 if (!mono_runtime_class_init_full (info->vtable, error)) {
2716 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2720 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2721 we always catch the exception and propagate it through the MonoError */
2722 gboolean catchExcInMonoError =
2723 (exc == NULL) && mono_threads_is_coop_enabled ();
2724 MonoObject *invoke_exc = NULL;
2725 if (catchExcInMonoError)
2728 /* The wrappers expect this to be initialized to NULL */
2732 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2733 if (info->dyn_call_info) {
2734 MonoMethodSignature *sig = mono_method_signature (method);
2736 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2739 guint8 retval [256];
2741 if (!dyn_runtime_invoke) {
2742 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2743 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2744 if (!mono_error_ok (error))
2748 /* Convert the arguments to the format expected by start_dyn_call () */
2749 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2752 args [pindex ++] = &obj;
2753 for (i = 0; i < sig->param_count; ++i) {
2754 MonoType *t = sig->params [i];
2757 args [pindex ++] = ¶ms [i];
2758 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2759 args [pindex ++] = ¶ms [i];
2761 args [pindex ++] = params [i];
2765 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2767 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2769 dyn_runtime_invoke (buf, exc, info->compiled_method);
2770 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2772 if (catchExcInMonoError && *exc != NULL) {
2773 mono_error_set_exception_instance (error, (MonoException*) *exc);
2777 if (info->ret_box_class)
2778 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2780 return *(MonoObject**)retval;
2786 if (mono_llvm_only) {
2787 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2791 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2793 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2795 if (catchExcInMonoError && *exc != NULL)
2796 mono_error_set_exception_instance (error, (MonoException*) *exc);
2805 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2808 * mini_llvmonly_initial_imt_tramp:
2810 * This function is called the first time a call is made through an IMT trampoline.
2811 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2814 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2816 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2821 mono_vtable_build_imt_slot (info->vtable, info->slot);
2823 imt = (gpointer*)info->vtable;
2824 imt -= MONO_IMT_SIZE;
2826 /* Return what the real IMT trampoline returns */
2827 ftndesc = imt [info->slot];
2830 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2831 /* Happens when the imt slot contains only a generic virtual method */
2833 return func ((gpointer *)ftndesc [1], imt_method);
2836 /* This is called indirectly through an imt slot. */
2838 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2842 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2843 while (arg [i] && arg [i] != imt_method)
2850 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2852 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2854 //g_assert (arg [0] == imt_method);
2859 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2861 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2862 if (arg [0] == imt_method)
2869 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2871 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2872 if (arg [0] == imt_method)
2874 else if (arg [2] == imt_method)
2881 * A version of the imt trampoline used for generic virtual/variant iface methods.
2882 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2883 * in the search table. The original JIT code had a 'fallback' trampoline it could
2884 * call, but we can't do that, so we just return NULL, and the compiled code
2888 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2892 while (arg [i] && arg [i] != imt_method)
2901 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2905 int i, index, real_count;
2906 gboolean virtual_generic = FALSE;
2909 * Create an array which is passed to the imt trampoline functions.
2910 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2914 for (i = 0; i < count; ++i) {
2915 MonoIMTCheckItem *item = imt_entries [i];
2917 if (item->is_equals)
2919 if (item->has_target_code)
2920 virtual_generic = TRUE;
2924 * Initialize all vtable entries reachable from this imt slot, so the compiled
2925 * code doesn't have to check it.
2927 for (i = 0; i < count; ++i) {
2928 MonoIMTCheckItem *item = imt_entries [i];
2931 if (!item->is_equals || item->has_target_code)
2933 vt_slot = item->value.vtable_slot;
2934 mono_init_vtable_slot (vtable, vt_slot);
2937 /* Save the entries into an array */
2938 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2940 for (i = 0; i < count; ++i) {
2941 MonoIMTCheckItem *item = imt_entries [i];
2943 if (!item->is_equals)
2946 g_assert (item->key);
2947 buf [(index * 2)] = item->key;
2948 if (item->has_target_code)
2949 buf [(index * 2) + 1] = item->value.target_code;
2951 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2954 buf [(index * 2)] = NULL;
2955 buf [(index * 2) + 1] = fail_tramp;
2958 * Return a function descriptor for a C function with 'buf' as its argument.
2959 * It will by called by JITted code.
2961 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2962 switch (real_count) {
2964 res [0] = mono_llvmonly_imt_tramp_1;
2967 res [0] = mono_llvmonly_imt_tramp_2;
2970 res [0] = mono_llvmonly_imt_tramp_3;
2973 res [0] = mono_llvmonly_imt_tramp;
2976 if (virtual_generic || fail_tramp)
2977 res [0] = mono_llvmonly_fallback_imt_tramp;
2983 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2985 MonoException *exc = NULL;
2987 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2988 MONO_SIG_HANDLER_GET_CONTEXT;
2990 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2992 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2994 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2995 if (mono_arch_is_int_overflow (ctx, info))
2997 * The spec says this throws ArithmeticException, but MS throws the derived
2998 * OverflowException.
3000 exc = mono_get_exception_overflow ();
3002 exc = mono_get_exception_divide_by_zero ();
3004 exc = mono_get_exception_divide_by_zero ();
3008 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3011 mono_handle_native_crash ("SIGFPE", ctx, info);
3012 if (mono_do_crash_chaining) {
3013 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3018 mono_arch_handle_exception (ctx, exc);
3021 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3024 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3026 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3027 MONO_SIG_HANDLER_GET_CONTEXT;
3029 if (mono_runtime_get_no_exec ())
3033 mono_handle_native_crash ("SIGILL", ctx, info);
3034 if (mono_do_crash_chaining) {
3035 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3039 g_assert_not_reached ();
3042 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3043 #define HAVE_SIG_INFO
3046 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3049 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3050 gpointer fault_addr = NULL;
3051 #ifdef HAVE_SIG_INFO
3052 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3056 MONO_SIG_HANDLER_GET_CONTEXT;
3058 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3059 if (mono_arch_is_single_step_event (info, ctx)) {
3060 mono_debugger_agent_single_step_event (ctx);
3062 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3063 mono_debugger_agent_breakpoint_hit (ctx);
3068 #if defined(HAVE_SIG_INFO)
3069 #if !defined(HOST_WIN32)
3070 fault_addr = info->si_addr;
3071 if (mono_aot_is_pagefault (info->si_addr)) {
3072 mono_aot_handle_pagefault (info->si_addr);
3077 /* The thread might no be registered with the runtime */
3078 if (!mono_domain_get () || !jit_tls) {
3079 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3081 mono_handle_native_crash ("SIGSEGV", ctx, info);
3082 if (mono_do_crash_chaining) {
3083 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3089 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3091 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3092 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3095 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3096 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3097 fault_addr = info->si_addr;
3098 if (fault_addr == NULL) {
3101 mono_sigctx_to_monoctx (ctx, &mctx);
3103 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3107 if (jit_tls->stack_size &&
3108 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3110 * The hard-guard page has been hit: there is not much we can do anymore
3111 * Print a hopefully clear message and abort.
3113 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3114 g_assert_not_reached ();
3116 /* The original handler might not like that it is executed on an altstack... */
3117 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3120 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3125 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3128 mono_handle_native_crash ("SIGSEGV", ctx, info);
3130 if (mono_do_crash_chaining) {
3131 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3136 mono_arch_handle_exception (ctx, NULL);
3140 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3143 MONO_SIG_HANDLER_GET_CONTEXT;
3145 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3147 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3149 mono_arch_handle_exception (ctx, exc);
3151 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3154 #ifndef DISABLE_REMOTING
3155 /* mono_jit_create_remoting_trampoline:
3156 * @method: pointer to the method info
3158 * Creates a trampoline which calls the remoting functions. This
3159 * is used in the vtable of transparent proxies.
3161 * Returns: a pointer to the newly created code
3164 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3167 guint8 *addr = NULL;
3171 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3172 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3176 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3177 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3178 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3181 addr = (guint8 *)mono_compile_method_checked (nm, error);
3182 return_val_if_nok (error, NULL);
3183 return mono_get_addr_from_ftnptr (addr);
3187 static G_GNUC_UNUSED void
3188 no_imt_trampoline (void)
3190 g_assert_not_reached ();
3193 static G_GNUC_UNUSED void
3194 no_vcall_trampoline (void)
3196 g_assert_not_reached ();
3199 static gpointer *vtable_trampolines;
3200 static int vtable_trampolines_size;
3203 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3205 int index = slot_index + MONO_IMT_SIZE;
3207 if (mono_llvm_only) {
3208 if (slot_index < 0) {
3209 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3210 // FIXME: Memory management
3211 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3212 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3215 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3217 mono_memory_barrier ();
3224 g_assert (slot_index >= - MONO_IMT_SIZE);
3225 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3227 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3231 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3232 while (new_size <= index)
3234 new_table = g_new0 (gpointer, new_size);
3236 if (vtable_trampolines)
3237 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3238 g_free (vtable_trampolines);
3239 mono_memory_barrier ();
3240 vtable_trampolines = (void **)new_table;
3241 vtable_trampolines_size = new_size;
3246 if (!vtable_trampolines [index])
3247 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3248 return vtable_trampolines [index];
3252 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3254 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3258 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3263 gpointer *imt = (gpointer*)vt;
3264 imt -= MONO_IMT_SIZE;
3266 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3270 is_callee_gsharedvt_variable (gpointer addr)
3273 gboolean callee_gsharedvt;
3275 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3277 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3278 if (callee_gsharedvt)
3279 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3280 return callee_gsharedvt;
3284 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3286 gpointer arg = NULL;
3288 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3289 arg = mini_method_get_rgctx (method);
3292 * Avoid adding gsharedvt in wrappers since they might not exist if
3293 * this delegate is called through a gsharedvt delegate invoke wrapper.
3294 * Instead, encode that the method is gsharedvt in del->extra_arg,
3295 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3297 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3298 g_assert ((((mgreg_t)arg) & 1) == 0);
3299 arg = (gpointer)(((mgreg_t)arg) | 1);
3305 mini_init_delegate (MonoDelegate *del)
3308 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3309 #ifdef ENABLE_INTERPRETER
3310 if (mono_use_interpreter)
3311 mono_interp_init_delegate (del);
3316 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3320 abs_offset = offset;
3322 abs_offset = - abs_offset;
3323 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3327 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3329 gboolean is_virtual_generic, is_interface, load_imt_reg;
3332 static guint8 **cache = NULL;
3333 static int cache_size = 0;
3338 if (MONO_TYPE_ISSTRUCT (sig->ret))
3341 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3342 is_interface = mono_class_is_interface (method->klass);
3343 load_imt_reg = is_virtual_generic || is_interface;
3346 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3348 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3350 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3351 g_assert (idx >= 0);
3353 /* Resize the cache to idx + 1 */
3354 if (cache_size < idx + 1) {
3356 if (cache_size < idx + 1) {
3358 int new_cache_size = idx + 1;
3360 new_cache = g_new0 (guint8*, new_cache_size);
3362 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3365 mono_memory_barrier ();
3367 cache_size = new_cache_size;
3375 /* FIXME Support more cases */
3376 if (mono_aot_only) {
3377 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3378 g_assert (cache [idx]);
3380 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3386 * mini_parse_debug_option:
3387 * @option: The option to parse.
3389 * Parses debug options for the mono runtime. The options are the same as for
3390 * the MONO_DEBUG environment variable.
3394 mini_parse_debug_option (const char *option)
3396 if (!strcmp (option, "handle-sigint"))
3397 debug_options.handle_sigint = TRUE;
3398 else if (!strcmp (option, "keep-delegates"))
3399 debug_options.keep_delegates = TRUE;
3400 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3401 debug_options.reverse_pinvoke_exceptions = TRUE;
3402 else if (!strcmp (option, "collect-pagefault-stats"))
3403 debug_options.collect_pagefault_stats = TRUE;
3404 else if (!strcmp (option, "break-on-unverified"))
3405 debug_options.break_on_unverified = TRUE;
3406 else if (!strcmp (option, "no-gdb-backtrace"))
3407 debug_options.no_gdb_backtrace = TRUE;
3408 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3409 debug_options.suspend_on_native_crash = TRUE;
3410 else if (!strcmp (option, "suspend-on-exception"))
3411 debug_options.suspend_on_exception = TRUE;
3412 else if (!strcmp (option, "suspend-on-unhandled"))
3413 debug_options.suspend_on_unhandled = TRUE;
3414 else if (!strcmp (option, "dont-free-domains"))
3415 mono_dont_free_domains = TRUE;
3416 else if (!strcmp (option, "dyn-runtime-invoke"))
3417 debug_options.dyn_runtime_invoke = TRUE;
3418 else if (!strcmp (option, "gdb"))
3419 debug_options.gdb = TRUE;
3420 else if (!strcmp (option, "lldb"))
3421 debug_options.lldb = TRUE;
3422 else if (!strcmp (option, "explicit-null-checks"))
3423 debug_options.explicit_null_checks = TRUE;
3424 else if (!strcmp (option, "gen-seq-points"))
3425 debug_options.gen_sdb_seq_points = TRUE;
3426 else if (!strcmp (option, "gen-compact-seq-points"))
3427 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3428 else if (!strcmp (option, "no-compact-seq-points"))
3429 debug_options.no_seq_points_compact_data = TRUE;
3430 else if (!strcmp (option, "single-imm-size"))
3431 debug_options.single_imm_size = TRUE;
3432 else if (!strcmp (option, "init-stacks"))
3433 debug_options.init_stacks = TRUE;
3434 else if (!strcmp (option, "casts"))
3435 debug_options.better_cast_details = TRUE;
3436 else if (!strcmp (option, "soft-breakpoints"))
3437 debug_options.soft_breakpoints = TRUE;
3438 else if (!strcmp (option, "check-pinvoke-callconv"))
3439 debug_options.check_pinvoke_callconv = TRUE;
3440 else if (!strcmp (option, "use-fallback-tls"))
3441 debug_options.use_fallback_tls = TRUE;
3442 else if (!strcmp (option, "debug-domain-unload"))
3443 mono_enable_debug_domain_unload (TRUE);
3444 else if (!strcmp (option, "partial-sharing"))
3445 mono_set_partial_sharing_supported (TRUE);
3446 else if (!strcmp (option, "align-small-structs"))
3447 mono_align_small_structs = TRUE;
3448 else if (!strcmp (option, "native-debugger-break"))
3449 debug_options.native_debugger_break = TRUE;
3450 else if (!strcmp (option, "disable_omit_fp"))
3451 debug_options.disable_omit_fp = TRUE;
3459 mini_parse_debug_options (void)
3461 char *options = g_getenv ("MONO_DEBUG");
3462 gchar **args, **ptr;
3467 args = g_strsplit (options, ",", -1);
3470 for (ptr = args; ptr && *ptr; ptr++) {
3471 const char *arg = *ptr;
3473 if (!mini_parse_debug_option (arg)) {
3474 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3475 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");
3484 mini_get_debug_options (void)
3486 return &debug_options;
3490 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3492 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3495 gpointer* desc = NULL;
3497 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3499 # if defined(__ppc64__) || defined(__powerpc64__)
3501 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3507 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3513 mini_get_addr_from_ftnptr (gpointer descr)
3515 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3516 return *(gpointer*)descr;
3523 register_jit_stats (void)
3525 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3526 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3527 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3528 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3529 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3530 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3531 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);
3532 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3533 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3534 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3535 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3536 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3537 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3538 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3539 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3540 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3541 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3542 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3543 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3544 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3545 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3546 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3547 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3548 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3549 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3550 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3551 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3552 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3553 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3554 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3555 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3556 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3557 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3558 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3559 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3560 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3561 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3562 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3563 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3564 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3565 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3566 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3567 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3568 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3569 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3570 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3571 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3572 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3573 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3574 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3575 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3576 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3577 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3578 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3579 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3580 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3581 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3582 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3583 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3584 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3585 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3588 static void runtime_invoke_info_free (gpointer value);
3591 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3593 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3594 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3596 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3600 class_method_pair_hash (gconstpointer data)
3602 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3604 return (gsize)pair->klass ^ (gsize)pair->method;
3608 mini_create_jit_domain_info (MonoDomain *domain)
3610 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3612 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3613 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3614 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3615 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3616 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3617 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3618 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3619 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3620 mono_jit_code_hash_init (&info->interp_code_hash);
3622 domain->runtime_info = info;
3626 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3628 MonoJumpList *jlist = (MonoJumpList *)value;
3629 g_slist_free (jlist->list);
3633 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3635 GSList *list = (GSList *)value;
3636 g_slist_free (list);
3640 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3642 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3643 mono_code_manager_destroy (di->code_mp);
3648 runtime_invoke_info_free (gpointer value)
3650 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3652 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3653 if (info->dyn_call_info)
3654 mono_arch_dyn_call_free (info->dyn_call_info);
3660 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3662 g_slist_free (value);
3666 mini_free_jit_domain_info (MonoDomain *domain)
3668 MonoJitDomainInfo *info = domain_jit_info (domain);
3670 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3671 g_hash_table_destroy (info->jump_target_hash);
3672 if (info->jump_target_got_slot_hash) {
3673 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3674 g_hash_table_destroy (info->jump_target_got_slot_hash);
3676 if (info->dynamic_code_hash) {
3677 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3678 g_hash_table_destroy (info->dynamic_code_hash);
3680 if (info->method_code_hash)
3681 g_hash_table_destroy (info->method_code_hash);
3682 g_hash_table_destroy (info->jump_trampoline_hash);
3683 g_hash_table_destroy (info->jit_trampoline_hash);
3684 g_hash_table_destroy (info->delegate_trampoline_hash);
3685 if (info->static_rgctx_trampoline_hash)
3686 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3687 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3688 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3689 g_hash_table_destroy (info->seq_points);
3690 g_hash_table_destroy (info->arch_seq_points);
3691 if (info->agent_info)
3692 mono_debugger_agent_free_domain_info (domain);
3693 if (info->gsharedvt_arg_tramp_hash)
3694 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3695 if (info->llvm_jit_callees) {
3696 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3697 g_hash_table_destroy (info->llvm_jit_callees);
3699 mono_internal_hash_table_destroy (&info->interp_code_hash);
3701 mono_llvm_free_domain_info (domain);
3704 g_free (domain->runtime_info);
3705 domain->runtime_info = NULL;
3708 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3711 code_manager_chunk_new (void *chunk, int size)
3713 mono_arch_code_chunk_new (chunk, size);
3717 code_manager_chunk_destroy (void *chunk)
3719 mono_arch_code_chunk_destroy (chunk);
3726 llvm_init_inner (void)
3728 if (!mono_llvm_load (NULL))
3739 * Load and initialize LLVM support.
3740 * Return TRUE on success.
3743 mini_llvm_init (void)
3746 static gboolean llvm_inited;
3747 static gboolean init_result;
3749 mono_loader_lock_if_inited ();
3751 init_result = llvm_init_inner ();
3754 mono_loader_unlock_if_inited ();
3762 mini_profiler_enable_with_options (const char* profile_options)
3764 mini_enable_profiler = TRUE;
3765 mini_profiler_options = g_strdup (profile_options);
3769 mini_init (const char *filename, const char *runtime_version)
3773 MonoRuntimeCallbacks callbacks;
3774 MonoThreadInfoRuntimeCallbacks ticallbacks;
3775 MonoCodeManagerCallbacks code_manager_callbacks;
3777 MONO_VES_INIT_BEGIN ();
3779 CHECKED_MONO_INIT ();
3781 #if defined(__linux__)
3782 if (access ("/proc/self/maps", F_OK) != 0) {
3783 g_print ("Mono requires /proc to be mounted.\n");
3788 #ifdef ENABLE_INTERPRETER
3789 mono_interp_init ();
3792 mono_os_mutex_init_recursive (&jit_mutex);
3794 mono_cross_helpers_run ();
3796 mono_counters_init ();
3800 mini_jit_init_job_control ();
3802 /* Happens when using the embedding interface */
3803 if (!default_opt_set)
3804 default_opt = mono_parse_default_optimizations (NULL);
3806 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3808 mono_set_generic_sharing_vt_supported (TRUE);
3811 mono_set_generic_sharing_vt_supported (TRUE);
3814 mono_tls_init_runtime_keys ();
3816 if (!global_codeman)
3817 global_codeman = mono_code_manager_new ();
3819 memset (&callbacks, 0, sizeof (callbacks));
3820 callbacks.create_ftnptr = mini_create_ftnptr;
3821 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3822 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3823 callbacks.set_cast_details = mono_set_cast_details;
3824 callbacks.debug_log = mono_debugger_agent_debug_log;
3825 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3826 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3827 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3828 callbacks.imt_entry_inited = mini_imt_entry_inited;
3829 callbacks.init_delegate = mini_init_delegate;
3830 #define JIT_INVOKE_WORKS
3831 #ifdef JIT_INVOKE_WORKS
3832 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3834 #define JIT_TRAMPOLINES_WORK
3835 #ifdef JIT_TRAMPOLINES_WORK
3836 callbacks.compile_method = mono_jit_compile_method;
3837 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3838 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3839 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3840 callbacks.free_method = mono_jit_free_method;
3841 #ifndef DISABLE_REMOTING
3842 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3846 mono_install_callbacks (&callbacks);
3848 memset (&ticallbacks, 0, sizeof (ticallbacks));
3849 ticallbacks.setup_async_callback = mono_setup_async_callback;
3850 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3851 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3852 ticallbacks.thread_state_init = mono_thread_state_init;
3855 mono_w32handle_init ();
3858 mono_thread_info_runtime_init (&ticallbacks);
3860 if (g_hasenv ("MONO_DEBUG")) {
3861 mini_parse_debug_options ();
3864 mono_code_manager_init ();
3866 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3867 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3868 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3869 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3871 mono_code_manager_install_callbacks (&code_manager_callbacks);
3875 mono_arch_cpu_init ();
3879 mono_unwind_init ();
3881 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3882 mono_lldb_init ("");
3883 mono_dont_free_domains = TRUE;
3886 #ifdef XDEBUG_ENABLED
3887 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3889 mono_xdebug_init (mono_xdebug);
3890 g_free (mono_xdebug);
3891 /* So methods for multiple domains don't have the same address */
3892 mono_dont_free_domains = TRUE;
3893 mono_using_xdebug = TRUE;
3894 } else if (mini_get_debug_options ()->gdb) {
3895 mono_xdebug_init ((char*)"gdb");
3896 mono_dont_free_domains = TRUE;
3897 mono_using_xdebug = TRUE;
3902 if (mono_use_llvm) {
3903 if (!mono_llvm_load (NULL)) {
3904 mono_use_llvm = FALSE;
3905 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3912 mono_trampolines_init ();
3914 if (default_opt & MONO_OPT_AOT)
3917 mono_debugger_agent_init ();
3919 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3920 mono_set_generic_sharing_supported (TRUE);
3923 mono_thread_info_signals_init ();
3925 #ifndef MONO_CROSS_COMPILE
3926 mono_runtime_install_handlers ();
3928 mono_threads_install_cleanup (mini_thread_cleanup);
3930 #ifdef JIT_TRAMPOLINES_WORK
3931 mono_install_create_domain_hook (mini_create_jit_domain_info);
3932 mono_install_free_domain_hook (mini_free_jit_domain_info);
3934 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3935 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3936 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3938 if (mini_profiler_enabled ()) {
3939 mono_profiler_load (mini_profiler_get_options ());
3940 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3943 if (debug_options.collect_pagefault_stats)
3944 mono_aot_set_make_unreadable (TRUE);
3946 if (runtime_version)
3947 domain = mono_init_version (filename, runtime_version);
3949 domain = mono_init_from_assembly (filename, filename);
3951 if (mono_aot_only) {
3952 /* This helps catch code allocation requests */
3953 mono_code_manager_set_read_only (domain->code_mp);
3954 mono_marshal_use_aot_wrappers (TRUE);
3957 if (mono_llvm_only) {
3958 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3959 mono_set_always_build_imt_trampolines (TRUE);
3960 } else if (mono_aot_only) {
3961 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3963 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3966 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3967 mono_arch_finish_init ();
3971 /* This must come after mono_init () in the aot-only case */
3972 mono_exceptions_init ();
3974 /* This should come after mono_init () too */
3978 mono_create_helper_signatures ();
3981 register_jit_stats ();
3983 #define JIT_CALLS_WORK
3984 #ifdef JIT_CALLS_WORK
3985 /* Needs to be called here since register_jit_icall depends on it */
3986 mono_marshal_init ();
3988 mono_arch_register_lowlevel_calls ();
3992 mono_generic_sharing_init ();
3995 #ifdef MONO_ARCH_SIMD_INTRINSICS
3996 mono_simd_intrinsics_init ();
3999 mono_tasklets_init ();
4001 register_trampolines (domain);
4003 if (mono_compile_aot)
4005 * Avoid running managed code when AOT compiling, since the platform
4006 * might only support aot-only execution.
4008 mono_runtime_set_no_exec (TRUE);
4010 mono_mem_account_register_counters ();
4012 #define JIT_RUNTIME_WORKS
4013 #ifdef JIT_RUNTIME_WORKS
4014 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4015 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4016 mono_error_assert_ok (&error);
4017 mono_thread_attach (domain);
4020 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4021 mono_runtime_setup_stat_profiler ();
4023 mono_profiler_runtime_initialized ();
4025 MONO_VES_INIT_END ();
4031 register_icalls (void)
4033 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4034 ves_icall_get_frame_info);
4035 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4036 ves_icall_get_trace);
4037 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4038 mono_runtime_install_handlers);
4039 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4040 mono_runtime_cleanup_handlers);
4042 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4043 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4044 mono_debugger_agent_unhandled_exception);
4048 * It's important that we pass `TRUE` as the last argument here, as
4049 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4050 * *did* emit a wrapper, we'd be looking at infinite recursion since
4051 * the wrapper would call the icall which would call the wrapper and
4054 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4055 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4057 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4058 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4059 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4060 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4061 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4062 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4064 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4065 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4066 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4067 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4068 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4069 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4070 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4071 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4072 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4074 // FIXME: This is broken
4075 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4078 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4079 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4080 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4081 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4082 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4083 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4085 if (mono_threads_is_coop_enabled ())
4086 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4088 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4089 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4090 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4091 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4092 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4093 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4095 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4096 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4097 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4100 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4101 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4102 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4103 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4106 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4107 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4108 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4109 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4110 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4113 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4114 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4117 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4118 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4119 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4122 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4123 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4126 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4127 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4128 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4129 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4130 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4131 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4132 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4135 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4136 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4137 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4140 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4141 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);
4143 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4144 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4146 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4147 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4149 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4150 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);
4152 #ifdef MONO_ARCH_EMULATE_FREM
4153 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4154 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4157 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4158 if (mono_arch_is_soft_float ()) {
4159 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4160 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4161 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4162 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4163 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4164 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4165 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4166 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4167 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4168 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4169 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4170 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4172 #if SIZEOF_VOID_P == 4
4173 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4176 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4177 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4178 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4179 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4180 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4181 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4182 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4183 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4184 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4185 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4187 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4188 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4189 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4190 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4191 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4193 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4194 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4195 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4196 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4199 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4201 #ifdef COMPRESSED_INTERFACE_BITMAP
4202 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4205 #if SIZEOF_REGISTER == 4
4206 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4208 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4211 /* other jit icalls */
4212 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4213 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4214 "ptr ptr ptr", FALSE);
4215 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4216 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4217 "ptr ptr ptr ptr", FALSE);
4218 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4219 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4220 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4221 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4222 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4223 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4224 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4225 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4226 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4227 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4228 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4229 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4230 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4231 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4232 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4233 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4234 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4235 register_icall (mono_break, "mono_break", NULL, TRUE);
4236 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4237 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4238 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4239 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4240 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4241 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4242 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4243 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4244 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4245 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4246 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4248 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int");
4250 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4251 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4252 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4253 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4254 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4256 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4258 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4259 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4260 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4261 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4263 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4264 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4265 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4266 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4267 /* This needs a wrapper so it can have a preserveall cconv */
4268 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4269 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4270 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4271 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4272 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4273 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4274 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4276 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4277 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4278 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4279 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4282 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4284 /* Register tls icalls */
4285 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4286 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4287 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4288 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4289 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4290 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4291 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4292 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4293 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4294 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4297 MonoJitStats mono_jit_stats = {0};
4300 print_jit_stats (void)
4302 if (mono_jit_stats.enabled) {
4303 g_print ("Mono Jit statistics\n");
4304 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4305 mono_jit_stats.max_ratio_method);
4306 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4307 mono_jit_stats.biggest_method);
4309 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4310 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4311 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4312 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4313 g_print ("Methods: %ld\n", mono_stats.method_count);
4314 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4315 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4316 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4318 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4319 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4320 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4322 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4323 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4324 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4325 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4327 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4328 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4329 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4330 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4331 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4332 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4333 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4334 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4336 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4337 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4338 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4340 g_free (mono_jit_stats.max_ratio_method);
4341 mono_jit_stats.max_ratio_method = NULL;
4342 g_free (mono_jit_stats.biggest_method);
4343 mono_jit_stats.biggest_method = NULL;
4348 mini_cleanup (MonoDomain *domain)
4350 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4351 mono_runtime_shutdown_stat_profiler ();
4354 cominterop_release_all_rcws ();
4357 #ifndef MONO_CROSS_COMPILE
4359 * mono_domain_finalize () needs to be called early since it needs the
4360 * execution engine still fully working (it may invoke managed finalizers).
4362 mono_domain_finalize (domain, 2000);
4365 /* This accesses metadata so needs to be called before runtime shutdown */
4368 #ifndef MONO_CROSS_COMPILE
4369 mono_runtime_cleanup (domain);
4372 mono_threadpool_cleanup ();
4374 mono_profiler_shutdown ();
4376 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4378 mono_icall_cleanup ();
4380 mono_runtime_cleanup_handlers ();
4382 #ifndef MONO_CROSS_COMPILE
4383 mono_domain_free (domain, TRUE);
4388 mono_llvm_cleanup ();
4391 mono_aot_cleanup ();
4393 mono_trampolines_cleanup ();
4395 mono_unwind_cleanup ();
4397 mono_code_manager_destroy (global_codeman);
4398 g_free (vtable_trampolines);
4400 mini_jit_cleanup ();
4402 mono_tramp_info_cleanup ();
4404 mono_arch_cleanup ();
4406 mono_generic_sharing_cleanup ();
4410 mono_trace_cleanup ();
4412 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4414 if (mono_inject_async_exc_method)
4415 mono_method_desc_free (mono_inject_async_exc_method);
4417 mono_tls_free_keys ();
4419 mono_os_mutex_destroy (&jit_mutex);
4421 mono_code_manager_cleanup ();
4424 mono_w32handle_cleanup ();
4429 mono_set_defaults (int verbose_level, guint32 opts)
4431 mini_verbose = verbose_level;
4432 mono_set_optimizations (opts);
4436 mono_disable_optimizations (guint32 opts)
4438 default_opt &= ~opts;
4442 mono_set_optimizations (guint32 opts)
4445 default_opt_set = TRUE;
4446 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4447 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4450 mono_set_generic_sharing_vt_supported (TRUE);
4455 mono_set_verbose_level (guint32 level)
4457 mini_verbose = level;
4461 * mono_get_runtime_build_info:
4462 * The returned string is owned by the caller. The returned string
4463 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4464 * \returns the runtime version + build date in string format.
4467 mono_get_runtime_build_info (void)
4469 if (mono_build_date)
4470 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4472 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4476 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4478 GHashTable *assemblies = (GHashTable*)user_data;
4479 MonoImage *image = mono_assembly_get_image (ass);
4480 MonoMethod *method, *invoke;
4483 if (g_hash_table_lookup (assemblies, ass))
4486 g_hash_table_insert (assemblies, ass, ass);
4488 if (mini_verbose > 0)
4489 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4491 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4494 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4496 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4499 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4501 if (method->is_generic || mono_class_is_gtd (method->klass))
4505 if (mini_verbose > 1) {
4506 char * desc = mono_method_full_name (method, TRUE);
4507 g_print ("Compiling %d %s\n", count, desc);
4510 mono_compile_method_checked (method, &error);
4511 if (!is_ok (&error)) {
4512 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4515 if (strcmp (method->name, "Finalize") == 0) {
4516 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4517 mono_compile_method_checked (invoke, &error);
4518 mono_error_assert_ok (&error);
4520 #ifndef DISABLE_REMOTING
4521 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4522 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4523 mono_compile_method_checked (invoke, &error);
4524 mono_error_assert_ok (&error);
4529 /* Load and precompile referenced assemblies as well */
4530 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4531 mono_assembly_load_reference (image, i);
4532 if (image->references [i])
4533 mono_precompile_assembly (image->references [i], assemblies);
4537 void mono_precompile_assemblies ()
4539 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4541 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4543 g_hash_table_destroy (assemblies);
4548 * Have to export this for AOT.
4551 mono_personality (void)
4554 g_assert_not_reached ();
4558 static MonoBreakPolicy
4559 always_insert_breakpoint (MonoMethod *method)
4561 return MONO_BREAK_POLICY_ALWAYS;
4564 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4567 * mono_set_break_policy:
4568 * \param policy_callback the new callback function
4570 * Allow embedders to decide whether to actually obey breakpoint instructions
4571 * (both break IL instructions and \c Debugger.Break method calls), for example
4572 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4573 * untrusted or semi-trusted code.
4575 * \p policy_callback will be called every time a break point instruction needs to
4576 * be inserted with the method argument being the method that calls \c Debugger.Break
4577 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4578 * if it wants the breakpoint to not be effective in the given method.
4579 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4582 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4584 if (policy_callback)
4585 break_policy_func = policy_callback;
4587 break_policy_func = always_insert_breakpoint;
4591 mini_should_insert_breakpoint (MonoMethod *method)
4593 switch (break_policy_func (method)) {
4594 case MONO_BREAK_POLICY_ALWAYS:
4596 case MONO_BREAK_POLICY_NEVER:
4598 case MONO_BREAK_POLICY_ON_DBG:
4599 g_warning ("mdb no longer supported");
4602 g_warning ("Incorrect value returned from break policy callback");
4607 // Custom handlers currently only implemented by Windows.
4610 mono_runtime_install_custom_handlers (const char *handlers)
4616 mono_runtime_install_custom_handlers_usage (void)
4619 "Custom Handlers:\n"
4620 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4621 " separated list of available handlers to install.\n"
4623 "No handlers supported on current platform.\n");
4625 #endif /* HOST_WIN32 */