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 return (ji->type << 8) | g_str_hash (ji->data.target);
1241 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1242 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1244 printf ("info type: %d\n", ji->type);
1245 mono_print_ji (ji); printf ("\n");
1246 g_assert_not_reached ();
1252 * mono_patch_info_equal:
1254 * This might fail to recognize equivalent patches, i.e. floats, so its only
1255 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1259 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1261 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1262 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1264 if (ji1->type != ji2->type)
1267 switch (ji1->type) {
1268 case MONO_PATCH_INFO_RVA:
1269 case MONO_PATCH_INFO_LDSTR:
1270 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1271 case MONO_PATCH_INFO_LDTOKEN:
1272 case MONO_PATCH_INFO_DECLSEC:
1273 if ((ji1->data.token->image != ji2->data.token->image) ||
1274 (ji1->data.token->token != ji2->data.token->token) ||
1275 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1276 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1277 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1280 case MONO_PATCH_INFO_INTERNAL_METHOD:
1281 return g_str_equal (ji1->data.name, ji2->data.name);
1282 case MONO_PATCH_INFO_RGCTX_FETCH:
1283 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1284 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1285 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1287 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);
1289 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1290 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1291 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1293 return c1->sig == c2->sig && c1->method == c2->method;
1295 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1296 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1297 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1298 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;
1299 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1300 return ji1->data.index == ji2->data.index;
1301 case MONO_PATCH_INFO_VIRT_METHOD:
1302 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1303 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1304 if (ji1->data.target == ji2->data.target)
1306 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1307 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1308 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1310 if (ji1->data.target != ji2->data.target)
1319 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1321 unsigned char *ip = patch_info->ip.i + code;
1322 gconstpointer target = NULL;
1326 switch (patch_info->type) {
1327 case MONO_PATCH_INFO_BB:
1329 * FIXME: This could be hit for methods without a prolog. Should use -1
1330 * but too much code depends on a 0 initial value.
1332 //g_assert (patch_info->data.bb->native_offset);
1333 target = patch_info->data.bb->native_offset + code;
1335 case MONO_PATCH_INFO_ABS:
1336 target = patch_info->data.target;
1338 case MONO_PATCH_INFO_LABEL:
1339 target = patch_info->data.inst->inst_c0 + code;
1341 case MONO_PATCH_INFO_IP:
1344 case MONO_PATCH_INFO_METHOD_REL:
1345 target = code + patch_info->data.offset;
1347 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1348 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1350 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1351 g_assert_not_reached ();
1353 target = mono_icall_get_wrapper (mi);
1356 case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
1357 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1359 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1360 g_assert_not_reached ();
1365 case MONO_PATCH_INFO_METHOD_JUMP:
1366 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1367 if (!mono_error_ok (error))
1370 case MONO_PATCH_INFO_METHOD:
1371 if (patch_info->data.method == method) {
1374 /* get the trampoline to the method from the domain */
1375 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1376 if (!mono_error_ok (error))
1380 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1383 mono_domain_lock (domain);
1384 if (!domain_jit_info (domain)->method_code_hash)
1385 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1386 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1388 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1389 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1391 mono_domain_unlock (domain);
1395 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1396 g_assert (mono_threads_is_coop_enabled ());
1397 target = (gpointer)&mono_polling_required;
1399 case MONO_PATCH_INFO_SWITCH: {
1400 gpointer *jump_table;
1402 if (method && method->dynamic) {
1403 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1405 if (mono_aot_only) {
1406 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1408 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1412 for (i = 0; i < patch_info->data.table->table_size; i++) {
1413 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1416 target = jump_table;
1419 case MONO_PATCH_INFO_METHODCONST:
1420 case MONO_PATCH_INFO_CLASS:
1421 case MONO_PATCH_INFO_IMAGE:
1422 case MONO_PATCH_INFO_FIELD:
1423 case MONO_PATCH_INFO_SIGNATURE:
1424 case MONO_PATCH_INFO_AOT_MODULE:
1425 target = patch_info->data.target;
1427 case MONO_PATCH_INFO_IID:
1428 mono_class_init (patch_info->data.klass);
1429 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1431 case MONO_PATCH_INFO_ADJUSTED_IID:
1432 mono_class_init (patch_info->data.klass);
1433 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1435 case MONO_PATCH_INFO_VTABLE:
1436 target = mono_class_vtable (domain, patch_info->data.klass);
1439 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1440 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1442 if (del_tramp->is_virtual)
1443 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1445 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1448 case MONO_PATCH_INFO_SFLDA: {
1449 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1451 if (mono_class_field_is_special_static (patch_info->data.field)) {
1452 gpointer addr = NULL;
1454 mono_domain_lock (domain);
1455 if (domain->special_static_fields)
1456 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1457 mono_domain_unlock (domain);
1463 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1464 /* Done by the generated code */
1468 if (!mono_runtime_class_init_full (vtable, error)) {
1473 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1476 case MONO_PATCH_INFO_RVA: {
1477 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1480 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1481 target = mono_image_rva_map (patch_info->data.token->image, rva);
1484 case MONO_PATCH_INFO_R4:
1485 case MONO_PATCH_INFO_R8:
1486 target = patch_info->data.target;
1488 case MONO_PATCH_INFO_EXC_NAME:
1489 target = patch_info->data.name;
1491 case MONO_PATCH_INFO_LDSTR:
1493 mono_ldstr_checked (domain, patch_info->data.token->image,
1494 mono_metadata_token_index (patch_info->data.token->token), error);
1496 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1498 MonoClass *handle_class;
1500 handle = mono_ldtoken_checked (patch_info->data.token->image,
1501 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1502 if (!mono_error_ok (error))
1504 mono_class_init (handle_class);
1505 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1507 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1508 if (!mono_error_ok (error))
1512 case MONO_PATCH_INFO_LDTOKEN: {
1514 MonoClass *handle_class;
1516 handle = mono_ldtoken_checked (patch_info->data.token->image,
1517 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1518 if (!mono_error_ok (error))
1519 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1520 mono_class_init (handle_class);
1525 case MONO_PATCH_INFO_DECLSEC:
1526 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1528 case MONO_PATCH_INFO_ICALL_ADDR:
1529 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1530 /* run_cctors == 0 -> AOT */
1531 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1532 const char *exc_class;
1533 const char *exc_arg;
1536 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1538 if (mono_aot_only) {
1539 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1542 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));
1548 target = mono_lookup_internal_call (patch_info->data.method);
1550 if (!target && run_cctors)
1551 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1554 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1555 target = mono_thread_interruption_request_flag ();
1557 case MONO_PATCH_INFO_METHOD_RGCTX: {
1558 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1561 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1564 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1565 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1567 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1570 case MONO_PATCH_INFO_BB_OVF:
1571 case MONO_PATCH_INFO_EXC_OVF:
1572 case MONO_PATCH_INFO_GOT_OFFSET:
1573 case MONO_PATCH_INFO_NONE:
1575 case MONO_PATCH_INFO_RGCTX_FETCH: {
1576 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1578 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1581 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1582 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1584 /* AOT, not needed */
1587 target = mono_arch_get_seq_point_info (domain, code);
1590 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1591 int card_table_shift_bits;
1592 gpointer card_table_mask;
1594 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1597 case MONO_PATCH_INFO_GC_NURSERY_START: {
1601 target = mono_gc_get_nursery (&shift_bits, &size);
1604 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1608 mono_gc_get_nursery (&shift_bits, &size);
1610 target = (gpointer)(mgreg_t)shift_bits;
1613 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1614 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1617 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1621 case MONO_PATCH_INFO_LDSTR_LIT: {
1625 len = strlen ((const char *)patch_info->data.target);
1626 s = (char *)mono_domain_alloc0 (domain, len + 1);
1627 memcpy (s, patch_info->data.target, len);
1632 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1633 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1635 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1636 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1638 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1639 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1641 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1642 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1648 g_assert_not_reached ();
1651 return (gpointer)target;
1655 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1657 MonoGenericInst *inst;
1660 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1662 if (context && context->class_inst) {
1663 inst = context->class_inst;
1664 for (i = 0; i < inst->type_argc; ++i) {
1665 MonoType *type = inst->type_argv [i];
1667 if (mini_is_gsharedvt_gparam (type))
1668 gsctx->is_gsharedvt = TRUE;
1671 if (context && context->method_inst) {
1672 inst = context->method_inst;
1674 for (i = 0; i < inst->type_argc; ++i) {
1675 MonoType *type = inst->type_argv [i];
1677 if (mini_is_gsharedvt_gparam (type))
1678 gsctx->is_gsharedvt = TRUE;
1684 * LOCKING: Acquires the jit code hash lock.
1687 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1690 static gboolean inited = FALSE;
1691 static int lookups = 0;
1692 static int failed_lookups = 0;
1694 mono_domain_jit_code_hash_lock (domain);
1695 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1696 if (!ji && shared) {
1697 /* Try generic sharing */
1698 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1699 if (ji && !ji->has_generic_jit_info)
1702 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1703 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1711 mono_domain_jit_code_hash_unlock (domain);
1717 lookup_method (MonoDomain *domain, MonoMethod *method)
1722 ji = mini_lookup_method (domain, method, NULL);
1725 if (!mono_method_is_generic_sharable (method, FALSE))
1727 shared = mini_get_shared_method (method);
1728 ji = mini_lookup_method (domain, method, shared);
1735 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1737 return lookup_method (domain, method);
1741 static FILE* perf_map_file;
1744 mono_enable_jit_map (void)
1746 if (!perf_map_file) {
1748 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1750 perf_map_file = fopen (name, "w");
1755 mono_emit_jit_tramp (void *start, int size, const char *desc)
1758 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1762 mono_emit_jit_map (MonoJitInfo *jinfo)
1764 if (perf_map_file) {
1765 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1766 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1772 mono_jit_map_is_enabled (void)
1774 return perf_map_file != NULL;
1780 no_gsharedvt_in_wrapper (void)
1782 g_assert_not_reached ();
1788 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.
1789 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1790 Dependency management in this case is too complex to justify implementing it.
1792 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1795 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1796 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1797 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1798 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1803 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1804 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1805 int threads_waiting; /* Number of threads waiting on this job */
1806 gboolean has_cond; /* True if @cond was initialized */
1807 gboolean done; /* True if the method finished JIT'ing */
1808 MonoCoopCond cond; /* Cond sleeping threads wait one */
1809 } JitCompilationEntry;
1812 GPtrArray *in_flight_methods; //JitCompilationEntry*
1814 } JitCompilationData;
1816 static JitCompilationData compilation_data;
1817 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1820 mini_jit_init_job_control (void)
1822 mono_coop_mutex_init (&compilation_data.lock);
1823 compilation_data.in_flight_methods = g_ptr_array_new ();
1827 lock_compilation_data (void)
1829 mono_coop_mutex_lock (&compilation_data.lock);
1833 unlock_compilation_data (void)
1835 mono_coop_mutex_unlock (&compilation_data.lock);
1838 static JitCompilationEntry*
1839 find_method (MonoMethod *method, MonoDomain *domain)
1842 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1843 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1844 if (e->method == method && e->domain == domain)
1852 add_current_thread (MonoJitTlsData *jit_tls)
1854 ++jit_tls->active_jit_methods;
1858 unref_jit_entry (JitCompilationEntry *entry)
1861 if (entry->ref_count)
1863 if (entry->has_cond)
1864 mono_coop_cond_destroy (&entry->cond);
1869 * Returns true if this method waited successfully for another thread to JIT it
1872 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1874 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1875 JitCompilationEntry *entry;
1877 static gboolean inited;
1879 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1880 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1881 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1882 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1886 lock_compilation_data ();
1888 if (!(entry = find_method (method, domain))) {
1889 entry = g_new0 (JitCompilationEntry, 1);
1890 entry->method = method;
1891 entry->domain = domain;
1892 entry->compilation_count = entry->ref_count = 1;
1893 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1894 g_assert (find_method (method, domain) == entry);
1895 add_current_thread (jit_tls);
1897 unlock_compilation_data ();
1899 } else if (jit_tls->active_jit_methods > 0) {
1900 //We can't suspend the current thread if it's already JITing a method.
1901 //Dependency management is too compilated and we want to get rid of this anyways.
1902 ++entry->compilation_count;
1903 ++jit_methods_multiple;
1904 ++jit_tls->active_jit_methods;
1906 unlock_compilation_data ();
1909 ++jit_methods_waited;
1912 if (!entry->has_cond) {
1913 mono_coop_cond_init (&entry->cond);
1914 entry->has_cond = TRUE;
1918 ++entry->threads_waiting;
1920 g_assert (entry->has_cond);
1921 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1922 --entry->threads_waiting;
1925 unref_jit_entry (entry);
1926 unlock_compilation_data ();
1929 ++jit_spurious_wakeups;
1936 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1938 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1940 lock_compilation_data ();
1942 g_assert (jit_tls->active_jit_methods > 0);
1943 --jit_tls->active_jit_methods;
1945 JitCompilationEntry *entry = find_method (method, target_domain);
1946 g_assert (entry); // It would be weird to fail
1949 if (entry->threads_waiting) {
1950 g_assert (entry->has_cond);
1951 mono_coop_cond_broadcast (&entry->cond);
1954 if (--entry->compilation_count == 0) {
1955 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1956 unref_jit_entry (entry);
1959 unlock_compilation_data ();
1964 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1966 MonoDomain *target_domain, *domain = mono_domain_get ();
1968 gpointer code = NULL, p;
1970 MonoJitICallInfo *callinfo = NULL;
1971 WrapperInfo *winfo = NULL;
1975 #ifdef ENABLE_INTERPRETER
1976 if (mono_use_interpreter && !jit_only) {
1977 code = mono_interp_create_method_pointer (method, error);
1984 /* Should be handled by the caller */
1985 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
1988 * ICALL wrappers are handled specially, since there is only one copy of them
1989 * shared by all appdomains.
1991 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1992 winfo = mono_marshal_get_wrapper_info (method);
1993 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
1994 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
1995 g_assert (callinfo);
1997 /* Must be domain neutral since there is only one copy */
1998 opt |= MONO_OPT_SHARED;
2000 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2001 opt &= ~MONO_OPT_SHARED;
2004 if (opt & MONO_OPT_SHARED)
2005 target_domain = mono_get_root_domain ();
2007 target_domain = domain;
2009 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2010 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2013 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2014 MonoGenericContext *ctx = NULL;
2015 if (method->is_inflated)
2016 ctx = mono_method_get_context (method);
2017 method = info->d.synchronized_inner.method;
2019 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2020 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2026 info = lookup_method (target_domain, method);
2028 /* We can't use a domain specific method in another domain */
2029 if (! ((domain != target_domain) && !info->domain_neutral)) {
2032 mono_jit_stats.methods_lookups++;
2033 vtable = mono_class_vtable_full (domain, method->klass, error);
2037 if (!mono_runtime_class_init_full (vtable, error))
2039 return mono_create_ftnptr (target_domain, info->code_start);
2043 #ifdef MONO_USE_AOT_COMPILER
2044 if (opt & MONO_OPT_AOT) {
2045 MonoDomain *domain = mono_domain_get ();
2047 mono_class_init (method->klass);
2049 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2052 if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
2054 * The suspend code needs to be able to lookup these methods by ip in async context,
2055 * so preload their jit info.
2057 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2062 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2063 * This is not a problem, since it will be initialized when the method is first
2064 * called by init_method ().
2066 if (!mono_llvm_only) {
2067 vtable = mono_class_vtable (domain, method->klass);
2069 if (!mono_runtime_class_init_full (vtable, error))
2078 if (!code && mono_llvm_only) {
2079 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2080 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2082 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2084 * These wrappers are only created for signatures which are in the program, but
2085 * sometimes we load methods too eagerly and have to create them even if they
2086 * will never be called.
2088 return no_gsharedvt_in_wrapper;
2094 if (wait_or_register_method_to_compile (method, target_domain))
2096 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2097 unregister_method_for_compile (method, target_domain);
2099 if (!mono_error_ok (error))
2102 if (!code && mono_llvm_only) {
2103 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2104 g_assert_not_reached ();
2110 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2114 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2116 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2120 p = mono_create_ftnptr (target_domain, code);
2123 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2124 mono_loader_lock ();
2126 if (!callinfo->wrapper) {
2127 callinfo->wrapper = p;
2128 mono_register_jit_icall_wrapper (callinfo, p);
2131 mono_loader_unlock ();
2138 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2142 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2147 * mono_jit_compile_method_jit_only:
2149 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2152 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2156 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2160 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2162 invalidated_delegate_trampoline (char *desc)
2164 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2165 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2171 * mono_jit_free_method:
2173 * Free all memory allocated by the JIT for METHOD.
2176 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2178 MonoJitDynamicMethodInfo *ji;
2179 gboolean destroy = TRUE;
2180 GHashTableIter iter;
2181 MonoJumpList *jlist;
2183 g_assert (method->dynamic);
2185 mono_domain_lock (domain);
2186 ji = mono_dynamic_code_hash_lookup (domain, method);
2187 mono_domain_unlock (domain);
2192 mono_debug_remove_method (method, domain);
2193 mono_lldb_remove_method (domain, method, ji);
2195 mono_domain_lock (domain);
2196 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2197 mono_domain_jit_code_hash_lock (domain);
2198 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2199 mono_domain_jit_code_hash_unlock (domain);
2200 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2202 /* requires the domain lock - took above */
2203 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2205 /* Remove jump targets in this method */
2206 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2207 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2208 GSList *tmp, *remove;
2211 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2212 guint8 *ip = (guint8 *)tmp->data;
2214 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2215 remove = g_slist_prepend (remove, tmp);
2217 for (tmp = remove; tmp; tmp = tmp->next) {
2218 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2220 g_slist_free (remove);
2222 mono_domain_unlock (domain);
2224 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2225 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2227 * Instead of freeing the code, change it to call an error routine
2228 * so people can fix their code.
2230 char *type = mono_type_full_name (&method->klass->byval_arg);
2231 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2234 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2240 * This needs to be done before freeing code_mp, since the code address is the
2241 * key in the table, so if we free the code_mp first, another thread can grab the
2242 * same code address and replace our entry in the table.
2244 mono_jit_info_table_remove (domain, ji->ji);
2247 mono_code_manager_destroy (ji->code_mp);
2252 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2254 MonoDomain *target_domain;
2257 if (default_opt & MONO_OPT_SHARED)
2258 target_domain = mono_get_root_domain ();
2260 target_domain = domain;
2262 info = lookup_method (target_domain, method);
2264 /* We can't use a domain specific method in another domain */
2265 if (! ((domain != target_domain) && !info->domain_neutral)) {
2266 mono_jit_stats.methods_lookups++;
2269 return info->code_start;
2278 static guint32 bisect_opt = 0;
2279 static GHashTable *bisect_methods_hash = NULL;
2282 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2285 char method_name [2048];
2288 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2289 g_assert (bisect_methods_hash);
2291 file = fopen (method_list_filename, "r");
2294 while (fgets (method_name, sizeof (method_name), file)) {
2295 size_t len = strlen (method_name);
2297 g_assert (method_name [len - 1] == '\n');
2298 method_name [len - 1] = 0;
2299 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2301 g_assert (feof (file));
2304 gboolean mono_do_single_method_regression = FALSE;
2305 guint32 mono_single_method_regression_opt = 0;
2306 MonoMethod *mono_current_single_method;
2307 GSList *mono_single_method_list;
2308 GHashTable *mono_single_method_hash;
2311 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2315 if (bisect_methods_hash) {
2316 char *name = mono_method_full_name (method, TRUE);
2317 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2320 return default_opt | bisect_opt;
2322 if (!mono_do_single_method_regression)
2324 if (!mono_current_single_method) {
2325 if (!mono_single_method_hash)
2326 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2327 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2328 g_hash_table_insert (mono_single_method_hash, method, method);
2329 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2333 if (method == mono_current_single_method)
2334 return mono_single_method_regression_opt;
2339 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2341 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2346 gpointer compiled_method;
2347 gpointer runtime_invoke;
2349 MonoDynCallInfo *dyn_call_info;
2350 MonoClass *ret_box_class;
2351 MonoMethodSignature *sig;
2352 gboolean gsharedvt_invoke;
2353 gpointer *wrapper_arg;
2354 } RuntimeInvokeInfo;
2356 static RuntimeInvokeInfo*
2357 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2360 RuntimeInvokeInfo *info;
2362 info = g_new0 (RuntimeInvokeInfo, 1);
2363 info->compiled_method = compiled_method;
2364 if (mono_llvm_only && method->string_ctor)
2365 info->sig = mono_marshal_get_string_ctor_signature (method);
2367 info->sig = mono_method_signature (method);
2369 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2370 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2371 if (!mono_error_ok (error))
2373 g_assert (info->vtable);
2375 MonoMethodSignature *sig = info->sig;
2379 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2380 * in full-aot mode, so we use a slower, but more generic wrapper if
2381 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2383 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2384 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2385 gboolean supported = TRUE;
2388 if (method->string_ctor)
2389 sig = mono_marshal_get_string_ctor_signature (method);
2391 for (i = 0; i < sig->param_count; ++i) {
2392 MonoType *t = sig->params [i];
2394 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2398 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2402 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2406 ret_type = sig->ret;
2407 switch (ret_type->type) {
2408 case MONO_TYPE_VOID:
2420 case MONO_TYPE_BOOLEAN:
2421 case MONO_TYPE_CHAR:
2424 info->ret_box_class = mono_class_from_mono_type (ret_type);
2427 info->ret_box_class = mono_defaults.int_class;
2429 case MONO_TYPE_STRING:
2430 case MONO_TYPE_CLASS:
2431 case MONO_TYPE_ARRAY:
2432 case MONO_TYPE_SZARRAY:
2433 case MONO_TYPE_OBJECT:
2435 case MONO_TYPE_GENERICINST:
2436 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2437 info->ret_box_class = mono_class_from_mono_type (ret_type);
2439 case MONO_TYPE_VALUETYPE:
2440 info->ret_box_class = mono_class_from_mono_type (ret_type);
2443 g_assert_not_reached ();
2447 if (!info->dyn_call_info) {
2448 if (mono_llvm_only) {
2449 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2450 g_assert_not_reached ();
2452 info->gsharedvt_invoke = TRUE;
2453 if (!callee_gsharedvt) {
2454 /* Invoke a gsharedvt out wrapper instead */
2455 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2456 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2458 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2459 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2461 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2462 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2463 g_free (wrapper_sig);
2465 info->compiled_method = mono_jit_compile_method (wrapper, error);
2466 if (!mono_error_ok (error)) {
2471 /* Gsharedvt methods can be invoked the same way */
2472 /* The out wrapper has the same signature as the compiled gsharedvt method */
2473 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2475 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2477 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2478 g_free (wrapper_sig);
2481 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2482 if (!mono_error_ok (error)) {
2492 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2494 MonoMethodSignature *sig = info->sig;
2495 MonoDomain *domain = mono_domain_get ();
2496 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2498 gpointer retval_ptr;
2499 guint8 retval [256];
2500 gpointer *param_refs;
2505 g_assert (info->gsharedvt_invoke);
2508 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2509 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2510 * signatures, so we only have to generate runtime invoke wrappers for these
2512 * This code also handles invocation of gsharedvt methods directly, no
2513 * out wrappers are used in that case.
2515 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2516 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2519 * The runtime invoke wrappers expects pointers to primitive types, so have to
2523 args [pindex ++] = &obj;
2524 if (sig->ret->type != MONO_TYPE_VOID) {
2525 retval_ptr = (gpointer)&retval;
2526 args [pindex ++] = &retval_ptr;
2528 for (i = 0; i < sig->param_count; ++i) {
2529 MonoType *t = sig->params [i];
2531 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2532 MonoClass *klass = mono_class_from_mono_type (t);
2533 guint8 *nullable_buf;
2536 size = mono_class_value_size (klass, NULL);
2537 nullable_buf = g_alloca (size);
2538 g_assert (nullable_buf);
2540 /* The argument pointed to by params [i] is either a boxed vtype or null */
2541 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2542 params [i] = nullable_buf;
2545 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2546 param_refs [i] = params [i];
2547 params [i] = &(param_refs [i]);
2549 args [pindex ++] = ¶ms [i];
2551 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2552 args [pindex ++] = &info->wrapper_arg;
2554 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2556 runtime_invoke (NULL, args, exc, info->compiled_method);
2560 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2561 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2563 return *(MonoObject**)retval;
2567 * mono_jit_runtime_invoke:
2568 * \param method: the method to invoke
2569 * \param obj: this pointer
2570 * \param params: array of parameter values.
2571 * \param exc: Set to the exception raised in the managed method.
2572 * \param error: error or caught exception object
2573 * If \p exc is NULL, \p error is thrown instead.
2574 * If coop is enabled, \p exc argument is ignored -
2575 * all exceptions are caught and propagated through \p error
2578 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2580 MonoMethod *invoke, *callee;
2581 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2582 MonoDomain *domain = mono_domain_get ();
2583 MonoJitDomainInfo *domain_info;
2584 RuntimeInvokeInfo *info, *info2;
2585 MonoJitInfo *ji = NULL;
2586 gboolean callee_gsharedvt = FALSE;
2588 #ifdef ENABLE_INTERPRETER
2589 if (mono_use_interpreter)
2590 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2595 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2596 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2600 domain_info = domain_jit_info (domain);
2602 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2605 if (mono_security_core_clr_enabled ()) {
2607 * This might be redundant since mono_class_vtable () already does this,
2608 * but keep it just in case for moonlight.
2610 mono_class_setup_vtable (method->klass);
2611 if (mono_class_has_failure (method->klass)) {
2612 mono_error_set_for_class_failure (error, method->klass);
2614 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2619 gpointer compiled_method;
2622 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2623 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2625 * Array Get/Set/Address methods. The JIT implements them using inline code
2626 * inside the runtime invoke wrappers, so no need to compile them.
2628 if (mono_aot_only) {
2630 * Call a wrapper, since the runtime invoke wrapper was not generated.
2632 MonoMethod *wrapper;
2634 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2635 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2643 compiled_method = mono_jit_compile_method (callee, error);
2644 if (!compiled_method) {
2645 g_assert (!mono_error_ok (error));
2649 if (mono_llvm_only) {
2650 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2651 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2652 if (callee_gsharedvt)
2653 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2656 if (!callee_gsharedvt)
2657 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2659 compiled_method = NULL;
2662 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2663 if (!mono_error_ok (error))
2666 mono_domain_lock (domain);
2667 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2668 mono_domain_unlock (domain);
2676 * We need this here because mono_marshal_get_runtime_invoke can place
2677 * the helper method in System.Object and not the target class.
2679 if (!mono_runtime_class_init_full (info->vtable, error)) {
2681 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2685 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2686 we always catch the exception and propagate it through the MonoError */
2687 gboolean catchExcInMonoError =
2688 (exc == NULL) && mono_threads_is_coop_enabled ();
2689 MonoObject *invoke_exc = NULL;
2690 if (catchExcInMonoError)
2693 /* The wrappers expect this to be initialized to NULL */
2697 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2698 if (info->dyn_call_info) {
2699 MonoMethodSignature *sig = mono_method_signature (method);
2701 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2704 guint8 retval [256];
2706 if (!dyn_runtime_invoke) {
2707 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2708 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2709 if (!mono_error_ok (error))
2713 /* Convert the arguments to the format expected by start_dyn_call () */
2714 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2717 args [pindex ++] = &obj;
2718 for (i = 0; i < sig->param_count; ++i) {
2719 MonoType *t = sig->params [i];
2722 args [pindex ++] = ¶ms [i];
2723 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2724 args [pindex ++] = ¶ms [i];
2726 args [pindex ++] = params [i];
2730 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2732 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2734 dyn_runtime_invoke (buf, exc, info->compiled_method);
2735 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2737 if (catchExcInMonoError && *exc != NULL) {
2738 mono_error_set_exception_instance (error, (MonoException*) *exc);
2742 if (info->ret_box_class)
2743 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2745 return *(MonoObject**)retval;
2751 if (mono_llvm_only) {
2752 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2756 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2758 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2760 if (catchExcInMonoError && *exc != NULL)
2761 mono_error_set_exception_instance (error, (MonoException*) *exc);
2770 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2773 * mini_llvmonly_initial_imt_tramp:
2775 * This function is called the first time a call is made through an IMT trampoline.
2776 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2779 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2781 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2786 mono_vtable_build_imt_slot (info->vtable, info->slot);
2788 imt = (gpointer*)info->vtable;
2789 imt -= MONO_IMT_SIZE;
2791 /* Return what the real IMT trampoline returns */
2792 ftndesc = imt [info->slot];
2795 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2796 /* Happens when the imt slot contains only a generic virtual method */
2798 return func ((gpointer *)ftndesc [1], imt_method);
2801 /* This is called indirectly through an imt slot. */
2803 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2807 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2808 while (arg [i] && arg [i] != imt_method)
2815 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2817 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2819 //g_assert (arg [0] == imt_method);
2824 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2826 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2827 if (arg [0] == imt_method)
2834 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2836 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2837 if (arg [0] == imt_method)
2839 else if (arg [2] == imt_method)
2846 * A version of the imt trampoline used for generic virtual/variant iface methods.
2847 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2848 * in the search table. The original JIT code had a 'fallback' trampoline it could
2849 * call, but we can't do that, so we just return NULL, and the compiled code
2853 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2857 while (arg [i] && arg [i] != imt_method)
2866 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2870 int i, index, real_count;
2871 gboolean virtual_generic = FALSE;
2874 * Create an array which is passed to the imt trampoline functions.
2875 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2879 for (i = 0; i < count; ++i) {
2880 MonoIMTCheckItem *item = imt_entries [i];
2882 if (item->is_equals)
2884 if (item->has_target_code)
2885 virtual_generic = TRUE;
2889 * Initialize all vtable entries reachable from this imt slot, so the compiled
2890 * code doesn't have to check it.
2892 for (i = 0; i < count; ++i) {
2893 MonoIMTCheckItem *item = imt_entries [i];
2896 if (!item->is_equals || item->has_target_code)
2898 vt_slot = item->value.vtable_slot;
2899 mono_init_vtable_slot (vtable, vt_slot);
2902 /* Save the entries into an array */
2903 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2905 for (i = 0; i < count; ++i) {
2906 MonoIMTCheckItem *item = imt_entries [i];
2908 if (!item->is_equals)
2911 g_assert (item->key);
2912 buf [(index * 2)] = item->key;
2913 if (item->has_target_code)
2914 buf [(index * 2) + 1] = item->value.target_code;
2916 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2919 buf [(index * 2)] = NULL;
2920 buf [(index * 2) + 1] = fail_tramp;
2923 * Return a function descriptor for a C function with 'buf' as its argument.
2924 * It will by called by JITted code.
2926 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2927 switch (real_count) {
2929 res [0] = mono_llvmonly_imt_tramp_1;
2932 res [0] = mono_llvmonly_imt_tramp_2;
2935 res [0] = mono_llvmonly_imt_tramp_3;
2938 res [0] = mono_llvmonly_imt_tramp;
2941 if (virtual_generic || fail_tramp)
2942 res [0] = mono_llvmonly_fallback_imt_tramp;
2948 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2950 MonoException *exc = NULL;
2952 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2953 MONO_SIG_HANDLER_GET_CONTEXT;
2955 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2957 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2959 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2960 if (mono_arch_is_int_overflow (ctx, info))
2962 * The spec says this throws ArithmeticException, but MS throws the derived
2963 * OverflowException.
2965 exc = mono_get_exception_overflow ();
2967 exc = mono_get_exception_divide_by_zero ();
2969 exc = mono_get_exception_divide_by_zero ();
2973 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
2976 mono_handle_native_crash ("SIGFPE", ctx, info);
2977 if (mono_do_crash_chaining) {
2978 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
2983 mono_arch_handle_exception (ctx, exc);
2986 MONO_EXIT_GC_UNSAFE_UNBALANCED;
2989 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
2991 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2992 MONO_SIG_HANDLER_GET_CONTEXT;
2994 if (mono_runtime_get_no_exec ())
2998 mono_handle_native_crash ("SIGILL", ctx, info);
2999 if (mono_do_crash_chaining) {
3000 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3004 g_assert_not_reached ();
3007 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3008 #define HAVE_SIG_INFO
3011 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3014 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3015 gpointer fault_addr = NULL;
3016 #ifdef HAVE_SIG_INFO
3017 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3021 MONO_SIG_HANDLER_GET_CONTEXT;
3023 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3024 if (mono_arch_is_single_step_event (info, ctx)) {
3025 mono_debugger_agent_single_step_event (ctx);
3027 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3028 mono_debugger_agent_breakpoint_hit (ctx);
3033 #if defined(HAVE_SIG_INFO)
3034 #if !defined(HOST_WIN32)
3035 fault_addr = info->si_addr;
3036 if (mono_aot_is_pagefault (info->si_addr)) {
3037 mono_aot_handle_pagefault (info->si_addr);
3042 /* The thread might no be registered with the runtime */
3043 if (!mono_domain_get () || !jit_tls) {
3044 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3046 mono_handle_native_crash ("SIGSEGV", ctx, info);
3047 if (mono_do_crash_chaining) {
3048 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3054 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3056 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3057 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3060 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3061 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3062 fault_addr = info->si_addr;
3063 if (fault_addr == NULL) {
3066 mono_sigctx_to_monoctx (ctx, &mctx);
3068 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3072 if (jit_tls->stack_size &&
3073 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3075 * The hard-guard page has been hit: there is not much we can do anymore
3076 * Print a hopefully clear message and abort.
3078 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3079 g_assert_not_reached ();
3081 /* The original handler might not like that it is executed on an altstack... */
3082 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3085 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3090 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3093 mono_handle_native_crash ("SIGSEGV", ctx, info);
3095 if (mono_do_crash_chaining) {
3096 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3101 mono_arch_handle_exception (ctx, NULL);
3105 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3108 MONO_SIG_HANDLER_GET_CONTEXT;
3110 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3112 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3114 mono_arch_handle_exception (ctx, exc);
3116 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3119 #ifndef DISABLE_REMOTING
3120 /* mono_jit_create_remoting_trampoline:
3121 * @method: pointer to the method info
3123 * Creates a trampoline which calls the remoting functions. This
3124 * is used in the vtable of transparent proxies.
3126 * Returns: a pointer to the newly created code
3129 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3132 guint8 *addr = NULL;
3136 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3137 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3141 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3142 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3143 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3146 addr = (guint8 *)mono_compile_method_checked (nm, error);
3147 return_val_if_nok (error, NULL);
3148 return mono_get_addr_from_ftnptr (addr);
3152 static G_GNUC_UNUSED void
3153 no_imt_trampoline (void)
3155 g_assert_not_reached ();
3158 static G_GNUC_UNUSED void
3159 no_vcall_trampoline (void)
3161 g_assert_not_reached ();
3164 static gpointer *vtable_trampolines;
3165 static int vtable_trampolines_size;
3168 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3170 int index = slot_index + MONO_IMT_SIZE;
3172 if (mono_llvm_only) {
3173 if (slot_index < 0) {
3174 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3175 // FIXME: Memory management
3176 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3177 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3180 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3182 mono_memory_barrier ();
3189 g_assert (slot_index >= - MONO_IMT_SIZE);
3190 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3192 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3196 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3197 while (new_size <= index)
3199 new_table = g_new0 (gpointer, new_size);
3201 if (vtable_trampolines)
3202 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3203 g_free (vtable_trampolines);
3204 mono_memory_barrier ();
3205 vtable_trampolines = (void **)new_table;
3206 vtable_trampolines_size = new_size;
3211 if (!vtable_trampolines [index])
3212 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3213 return vtable_trampolines [index];
3217 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3219 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3223 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3228 gpointer *imt = (gpointer*)vt;
3229 imt -= MONO_IMT_SIZE;
3231 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3235 is_callee_gsharedvt_variable (gpointer addr)
3238 gboolean callee_gsharedvt;
3240 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3242 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3243 if (callee_gsharedvt)
3244 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3245 return callee_gsharedvt;
3249 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3251 gpointer arg = NULL;
3253 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3254 arg = mini_method_get_rgctx (method);
3257 * Avoid adding gsharedvt in wrappers since they might not exist if
3258 * this delegate is called through a gsharedvt delegate invoke wrapper.
3259 * Instead, encode that the method is gsharedvt in del->extra_arg,
3260 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3262 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3263 g_assert ((((mgreg_t)arg) & 1) == 0);
3264 arg = (gpointer)(((mgreg_t)arg) | 1);
3270 mini_init_delegate (MonoDelegate *del)
3273 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3274 #ifdef ENABLE_INTERPRETER
3275 if (mono_use_interpreter)
3276 mono_interp_init_delegate (del);
3281 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3285 abs_offset = offset;
3287 abs_offset = - abs_offset;
3288 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3292 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3294 gboolean is_virtual_generic, is_interface, load_imt_reg;
3297 static guint8 **cache = NULL;
3298 static int cache_size = 0;
3303 if (MONO_TYPE_ISSTRUCT (sig->ret))
3306 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3307 is_interface = mono_class_is_interface (method->klass);
3308 load_imt_reg = is_virtual_generic || is_interface;
3311 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3313 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3315 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3316 g_assert (idx >= 0);
3318 /* Resize the cache to idx + 1 */
3319 if (cache_size < idx + 1) {
3321 if (cache_size < idx + 1) {
3323 int new_cache_size = idx + 1;
3325 new_cache = g_new0 (guint8*, new_cache_size);
3327 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3330 mono_memory_barrier ();
3332 cache_size = new_cache_size;
3340 /* FIXME Support more cases */
3341 if (mono_aot_only) {
3342 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3343 g_assert (cache [idx]);
3345 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3351 * mini_parse_debug_option:
3352 * @option: The option to parse.
3354 * Parses debug options for the mono runtime. The options are the same as for
3355 * the MONO_DEBUG environment variable.
3359 mini_parse_debug_option (const char *option)
3361 if (!strcmp (option, "handle-sigint"))
3362 debug_options.handle_sigint = TRUE;
3363 else if (!strcmp (option, "keep-delegates"))
3364 debug_options.keep_delegates = TRUE;
3365 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3366 debug_options.reverse_pinvoke_exceptions = TRUE;
3367 else if (!strcmp (option, "collect-pagefault-stats"))
3368 debug_options.collect_pagefault_stats = TRUE;
3369 else if (!strcmp (option, "break-on-unverified"))
3370 debug_options.break_on_unverified = TRUE;
3371 else if (!strcmp (option, "no-gdb-backtrace"))
3372 debug_options.no_gdb_backtrace = TRUE;
3373 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3374 debug_options.suspend_on_native_crash = TRUE;
3375 else if (!strcmp (option, "suspend-on-exception"))
3376 debug_options.suspend_on_exception = TRUE;
3377 else if (!strcmp (option, "suspend-on-unhandled"))
3378 debug_options.suspend_on_unhandled = TRUE;
3379 else if (!strcmp (option, "dont-free-domains"))
3380 mono_dont_free_domains = TRUE;
3381 else if (!strcmp (option, "dyn-runtime-invoke"))
3382 debug_options.dyn_runtime_invoke = TRUE;
3383 else if (!strcmp (option, "gdb"))
3384 debug_options.gdb = TRUE;
3385 else if (!strcmp (option, "lldb"))
3386 debug_options.lldb = TRUE;
3387 else if (!strcmp (option, "explicit-null-checks"))
3388 debug_options.explicit_null_checks = TRUE;
3389 else if (!strcmp (option, "gen-seq-points"))
3390 debug_options.gen_sdb_seq_points = TRUE;
3391 else if (!strcmp (option, "gen-compact-seq-points"))
3392 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3393 else if (!strcmp (option, "no-compact-seq-points"))
3394 debug_options.no_seq_points_compact_data = TRUE;
3395 else if (!strcmp (option, "single-imm-size"))
3396 debug_options.single_imm_size = TRUE;
3397 else if (!strcmp (option, "init-stacks"))
3398 debug_options.init_stacks = TRUE;
3399 else if (!strcmp (option, "casts"))
3400 debug_options.better_cast_details = TRUE;
3401 else if (!strcmp (option, "soft-breakpoints"))
3402 debug_options.soft_breakpoints = TRUE;
3403 else if (!strcmp (option, "check-pinvoke-callconv"))
3404 debug_options.check_pinvoke_callconv = TRUE;
3405 else if (!strcmp (option, "use-fallback-tls"))
3406 debug_options.use_fallback_tls = TRUE;
3407 else if (!strcmp (option, "debug-domain-unload"))
3408 mono_enable_debug_domain_unload (TRUE);
3409 else if (!strcmp (option, "partial-sharing"))
3410 mono_set_partial_sharing_supported (TRUE);
3411 else if (!strcmp (option, "align-small-structs"))
3412 mono_align_small_structs = TRUE;
3413 else if (!strcmp (option, "native-debugger-break"))
3414 debug_options.native_debugger_break = TRUE;
3415 else if (!strcmp (option, "disable_omit_fp"))
3416 debug_options.disable_omit_fp = TRUE;
3424 mini_parse_debug_options (void)
3426 char *options = g_getenv ("MONO_DEBUG");
3427 gchar **args, **ptr;
3432 args = g_strsplit (options, ",", -1);
3435 for (ptr = args; ptr && *ptr; ptr++) {
3436 const char *arg = *ptr;
3438 if (!mini_parse_debug_option (arg)) {
3439 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3440 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");
3449 mini_get_debug_options (void)
3451 return &debug_options;
3455 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3457 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3460 gpointer* desc = NULL;
3462 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3464 # if defined(__ppc64__) || defined(__powerpc64__)
3466 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3472 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3478 mini_get_addr_from_ftnptr (gpointer descr)
3480 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3481 return *(gpointer*)descr;
3488 register_jit_stats (void)
3490 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3491 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3492 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3493 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3494 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3495 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3496 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);
3497 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3498 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3499 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3500 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3501 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3502 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3503 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3504 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3505 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3506 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3507 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3508 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3509 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3510 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3511 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3512 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3513 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3514 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3515 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3516 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3517 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3518 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3519 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3520 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3521 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3522 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3523 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3524 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3525 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3526 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3527 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3528 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3529 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3530 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3531 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3532 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3533 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3534 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3535 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3536 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3537 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3538 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3539 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3540 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3541 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3542 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3543 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3544 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3545 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3546 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3547 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3548 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3549 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3550 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3553 static void runtime_invoke_info_free (gpointer value);
3556 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3558 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3559 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3561 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3565 class_method_pair_hash (gconstpointer data)
3567 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3569 return (gsize)pair->klass ^ (gsize)pair->method;
3573 mini_create_jit_domain_info (MonoDomain *domain)
3575 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3577 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3578 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3579 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3580 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3581 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3582 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3583 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3584 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3585 mono_jit_code_hash_init (&info->interp_code_hash);
3587 domain->runtime_info = info;
3591 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3593 MonoJumpList *jlist = (MonoJumpList *)value;
3594 g_slist_free (jlist->list);
3598 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3600 GSList *list = (GSList *)value;
3601 g_slist_free (list);
3605 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3607 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3608 mono_code_manager_destroy (di->code_mp);
3613 runtime_invoke_info_free (gpointer value)
3615 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3617 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3618 if (info->dyn_call_info)
3619 mono_arch_dyn_call_free (info->dyn_call_info);
3625 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3627 g_slist_free (value);
3631 mini_free_jit_domain_info (MonoDomain *domain)
3633 MonoJitDomainInfo *info = domain_jit_info (domain);
3635 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3636 g_hash_table_destroy (info->jump_target_hash);
3637 if (info->jump_target_got_slot_hash) {
3638 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3639 g_hash_table_destroy (info->jump_target_got_slot_hash);
3641 if (info->dynamic_code_hash) {
3642 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3643 g_hash_table_destroy (info->dynamic_code_hash);
3645 if (info->method_code_hash)
3646 g_hash_table_destroy (info->method_code_hash);
3647 g_hash_table_destroy (info->jump_trampoline_hash);
3648 g_hash_table_destroy (info->jit_trampoline_hash);
3649 g_hash_table_destroy (info->delegate_trampoline_hash);
3650 if (info->static_rgctx_trampoline_hash)
3651 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3652 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3653 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3654 g_hash_table_destroy (info->seq_points);
3655 g_hash_table_destroy (info->arch_seq_points);
3656 if (info->agent_info)
3657 mono_debugger_agent_free_domain_info (domain);
3658 if (info->gsharedvt_arg_tramp_hash)
3659 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3660 if (info->llvm_jit_callees) {
3661 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3662 g_hash_table_destroy (info->llvm_jit_callees);
3664 mono_internal_hash_table_destroy (&info->interp_code_hash);
3666 mono_llvm_free_domain_info (domain);
3669 g_free (domain->runtime_info);
3670 domain->runtime_info = NULL;
3673 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3676 code_manager_chunk_new (void *chunk, int size)
3678 mono_arch_code_chunk_new (chunk, size);
3682 code_manager_chunk_destroy (void *chunk)
3684 mono_arch_code_chunk_destroy (chunk);
3691 llvm_init_inner (void)
3693 if (!mono_llvm_load (NULL))
3704 * Load and initialize LLVM support.
3705 * Return TRUE on success.
3708 mini_llvm_init (void)
3711 static gboolean llvm_inited;
3712 static gboolean init_result;
3714 mono_loader_lock_if_inited ();
3716 init_result = llvm_init_inner ();
3719 mono_loader_unlock_if_inited ();
3727 mini_profiler_enable_with_options (const char* profile_options)
3729 mini_enable_profiler = TRUE;
3730 mini_profiler_options = g_strdup (profile_options);
3734 mini_init (const char *filename, const char *runtime_version)
3738 MonoRuntimeCallbacks callbacks;
3739 MonoThreadInfoRuntimeCallbacks ticallbacks;
3740 MonoCodeManagerCallbacks code_manager_callbacks;
3742 MONO_VES_INIT_BEGIN ();
3744 CHECKED_MONO_INIT ();
3746 #if defined(__linux__)
3747 if (access ("/proc/self/maps", F_OK) != 0) {
3748 g_print ("Mono requires /proc to be mounted.\n");
3753 #ifdef ENABLE_INTERPRETER
3754 mono_interp_init ();
3757 mono_os_mutex_init_recursive (&jit_mutex);
3759 mono_cross_helpers_run ();
3761 mono_counters_init ();
3765 mini_jit_init_job_control ();
3767 /* Happens when using the embedding interface */
3768 if (!default_opt_set)
3769 default_opt = mono_parse_default_optimizations (NULL);
3771 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3773 mono_set_generic_sharing_vt_supported (TRUE);
3776 mono_set_generic_sharing_vt_supported (TRUE);
3779 mono_tls_init_runtime_keys ();
3781 if (!global_codeman)
3782 global_codeman = mono_code_manager_new ();
3784 memset (&callbacks, 0, sizeof (callbacks));
3785 callbacks.create_ftnptr = mini_create_ftnptr;
3786 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3787 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3788 callbacks.set_cast_details = mono_set_cast_details;
3789 callbacks.debug_log = mono_debugger_agent_debug_log;
3790 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3791 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3792 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3793 callbacks.imt_entry_inited = mini_imt_entry_inited;
3794 callbacks.init_delegate = mini_init_delegate;
3795 #define JIT_INVOKE_WORKS
3796 #ifdef JIT_INVOKE_WORKS
3797 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3799 #define JIT_TRAMPOLINES_WORK
3800 #ifdef JIT_TRAMPOLINES_WORK
3801 callbacks.compile_method = mono_jit_compile_method;
3802 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3803 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3804 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3805 callbacks.free_method = mono_jit_free_method;
3806 #ifndef DISABLE_REMOTING
3807 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3811 mono_install_callbacks (&callbacks);
3813 memset (&ticallbacks, 0, sizeof (ticallbacks));
3814 ticallbacks.setup_async_callback = mono_setup_async_callback;
3815 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3816 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3817 ticallbacks.thread_state_init = mono_thread_state_init;
3820 mono_w32handle_init ();
3823 mono_threads_runtime_init (&ticallbacks);
3825 if (g_hasenv ("MONO_DEBUG")) {
3826 mini_parse_debug_options ();
3829 mono_code_manager_init ();
3831 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3832 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3833 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3834 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3836 mono_code_manager_install_callbacks (&code_manager_callbacks);
3840 mono_arch_cpu_init ();
3844 mono_unwind_init ();
3846 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3847 mono_lldb_init ("");
3848 mono_dont_free_domains = TRUE;
3851 #ifdef XDEBUG_ENABLED
3852 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3854 mono_xdebug_init (mono_xdebug);
3855 g_free (mono_xdebug);
3856 /* So methods for multiple domains don't have the same address */
3857 mono_dont_free_domains = TRUE;
3858 mono_using_xdebug = TRUE;
3859 } else if (mini_get_debug_options ()->gdb) {
3860 mono_xdebug_init ((char*)"gdb");
3861 mono_dont_free_domains = TRUE;
3862 mono_using_xdebug = TRUE;
3867 if (mono_use_llvm) {
3868 if (!mono_llvm_load (NULL)) {
3869 mono_use_llvm = FALSE;
3870 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3877 mono_trampolines_init ();
3879 if (default_opt & MONO_OPT_AOT)
3882 mono_debugger_agent_init ();
3884 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3885 mono_set_generic_sharing_supported (TRUE);
3888 mono_threads_signals_init ();
3890 #ifndef MONO_CROSS_COMPILE
3891 mono_runtime_install_handlers ();
3893 mono_threads_install_cleanup (mini_thread_cleanup);
3895 #ifdef JIT_TRAMPOLINES_WORK
3896 mono_install_create_domain_hook (mini_create_jit_domain_info);
3897 mono_install_free_domain_hook (mini_free_jit_domain_info);
3899 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3900 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3901 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3903 if (mini_profiler_enabled ()) {
3904 mono_profiler_load (mini_profiler_get_options ());
3905 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3908 if (debug_options.collect_pagefault_stats)
3909 mono_aot_set_make_unreadable (TRUE);
3911 if (runtime_version)
3912 domain = mono_init_version (filename, runtime_version);
3914 domain = mono_init_from_assembly (filename, filename);
3916 if (mono_aot_only) {
3917 /* This helps catch code allocation requests */
3918 mono_code_manager_set_read_only (domain->code_mp);
3919 mono_marshal_use_aot_wrappers (TRUE);
3922 if (mono_llvm_only) {
3923 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3924 mono_set_always_build_imt_trampolines (TRUE);
3925 } else if (mono_aot_only) {
3926 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3928 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3931 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3932 mono_arch_finish_init ();
3936 /* This must come after mono_init () in the aot-only case */
3937 mono_exceptions_init ();
3939 /* This should come after mono_init () too */
3943 mono_create_helper_signatures ();
3946 register_jit_stats ();
3948 #define JIT_CALLS_WORK
3949 #ifdef JIT_CALLS_WORK
3950 /* Needs to be called here since register_jit_icall depends on it */
3951 mono_marshal_init ();
3953 mono_arch_register_lowlevel_calls ();
3957 mono_generic_sharing_init ();
3960 #ifdef MONO_ARCH_SIMD_INTRINSICS
3961 mono_simd_intrinsics_init ();
3964 mono_tasklets_init ();
3966 register_trampolines (domain);
3968 if (mono_compile_aot)
3970 * Avoid running managed code when AOT compiling, since the platform
3971 * might only support aot-only execution.
3973 mono_runtime_set_no_exec (TRUE);
3975 mono_mem_account_register_counters ();
3977 #define JIT_RUNTIME_WORKS
3978 #ifdef JIT_RUNTIME_WORKS
3979 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
3980 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
3981 mono_error_assert_ok (&error);
3982 mono_thread_attach (domain);
3985 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
3986 mono_runtime_setup_stat_profiler ();
3988 mono_profiler_runtime_initialized ();
3990 MONO_VES_INIT_END ();
3996 register_icalls (void)
3998 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
3999 ves_icall_get_frame_info);
4000 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4001 ves_icall_get_trace);
4002 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4003 mono_runtime_install_handlers);
4004 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4005 mono_runtime_cleanup_handlers);
4007 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4008 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4009 mono_debugger_agent_unhandled_exception);
4013 * It's important that we pass `TRUE` as the last argument here, as
4014 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4015 * *did* emit a wrapper, we'd be looking at infinite recursion since
4016 * the wrapper would call the icall which would call the wrapper and
4019 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4020 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4022 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4023 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4024 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4025 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4026 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4027 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4029 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4030 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4031 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4032 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4033 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4034 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4035 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4036 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4037 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4039 // FIXME: This is broken
4040 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4043 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4044 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4045 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4046 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4047 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4048 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4050 if (mono_threads_is_coop_enabled ())
4051 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4053 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4054 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4055 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4056 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4057 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4058 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4060 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4061 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4062 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4065 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4066 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4067 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4068 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4071 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4072 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4073 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4074 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4075 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4078 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4079 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4082 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4083 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4084 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4087 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4088 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4091 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4092 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4093 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4094 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4095 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4096 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4097 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4100 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4101 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4102 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4105 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4106 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);
4108 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4109 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4111 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4112 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4114 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4115 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);
4117 #ifdef MONO_ARCH_EMULATE_FREM
4118 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4119 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4122 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4123 if (mono_arch_is_soft_float ()) {
4124 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4125 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4126 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4127 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4128 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4129 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4130 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4131 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4132 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4133 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4134 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4135 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4137 #if SIZEOF_VOID_P == 4
4138 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4141 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4142 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4143 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4144 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4145 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4146 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4147 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4148 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4149 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4150 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4152 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4153 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4154 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4155 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4156 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4158 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4159 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4160 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4161 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4164 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4166 #ifdef COMPRESSED_INTERFACE_BITMAP
4167 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4170 #if SIZEOF_REGISTER == 4
4171 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4173 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4176 /* other jit icalls */
4177 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4178 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4179 "ptr ptr ptr", FALSE);
4180 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4181 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4182 "ptr ptr ptr ptr", FALSE);
4183 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4184 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4185 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4186 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4187 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4188 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4189 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4190 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4191 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4192 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4193 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4194 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4195 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4196 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4197 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4198 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4199 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4200 register_icall (mono_break, "mono_break", NULL, TRUE);
4201 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4202 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4203 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4204 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4205 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4206 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4207 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4208 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4209 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4210 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4211 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4213 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int");
4215 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4216 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4217 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4218 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4219 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4221 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4223 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4224 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4225 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4226 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4228 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4229 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4230 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4231 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4232 /* This needs a wrapper so it can have a preserveall cconv */
4233 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4234 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4235 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4236 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4237 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4238 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4239 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4241 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4242 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4243 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4244 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4247 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4249 /* Register tls icalls */
4250 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4251 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4252 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4253 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4254 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4255 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4256 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4257 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4258 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4259 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4262 MonoJitStats mono_jit_stats = {0};
4265 print_jit_stats (void)
4267 if (mono_jit_stats.enabled) {
4268 g_print ("Mono Jit statistics\n");
4269 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4270 mono_jit_stats.max_ratio_method);
4271 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4272 mono_jit_stats.biggest_method);
4274 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4275 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4276 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4277 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4278 g_print ("Methods: %ld\n", mono_stats.method_count);
4279 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4280 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4281 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4283 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4284 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4285 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4287 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4288 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4289 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4290 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4292 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4293 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4294 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4295 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4296 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4297 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4298 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4299 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4301 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4302 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4303 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4305 g_free (mono_jit_stats.max_ratio_method);
4306 mono_jit_stats.max_ratio_method = NULL;
4307 g_free (mono_jit_stats.biggest_method);
4308 mono_jit_stats.biggest_method = NULL;
4313 mini_cleanup (MonoDomain *domain)
4315 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4316 mono_runtime_shutdown_stat_profiler ();
4319 cominterop_release_all_rcws ();
4322 #ifndef MONO_CROSS_COMPILE
4324 * mono_domain_finalize () needs to be called early since it needs the
4325 * execution engine still fully working (it may invoke managed finalizers).
4327 mono_domain_finalize (domain, 2000);
4330 /* This accesses metadata so needs to be called before runtime shutdown */
4333 #ifndef MONO_CROSS_COMPILE
4334 mono_runtime_cleanup (domain);
4337 mono_threadpool_cleanup ();
4339 mono_profiler_shutdown ();
4341 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4343 mono_icall_cleanup ();
4345 mono_runtime_cleanup_handlers ();
4347 #ifndef MONO_CROSS_COMPILE
4348 mono_domain_free (domain, TRUE);
4353 mono_llvm_cleanup ();
4356 mono_aot_cleanup ();
4358 mono_trampolines_cleanup ();
4360 mono_unwind_cleanup ();
4362 mono_code_manager_destroy (global_codeman);
4363 g_free (vtable_trampolines);
4365 mini_jit_cleanup ();
4367 mono_tramp_info_cleanup ();
4369 mono_arch_cleanup ();
4371 mono_generic_sharing_cleanup ();
4375 mono_trace_cleanup ();
4377 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4379 if (mono_inject_async_exc_method)
4380 mono_method_desc_free (mono_inject_async_exc_method);
4382 mono_tls_free_keys ();
4384 mono_os_mutex_destroy (&jit_mutex);
4386 mono_code_manager_cleanup ();
4389 mono_w32handle_cleanup ();
4394 mono_set_defaults (int verbose_level, guint32 opts)
4396 mini_verbose = verbose_level;
4397 mono_set_optimizations (opts);
4401 mono_disable_optimizations (guint32 opts)
4403 default_opt &= ~opts;
4407 mono_set_optimizations (guint32 opts)
4410 default_opt_set = TRUE;
4411 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4412 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4415 mono_set_generic_sharing_vt_supported (TRUE);
4420 mono_set_verbose_level (guint32 level)
4422 mini_verbose = level;
4426 * mono_get_runtime_build_info:
4427 * The returned string is owned by the caller. The returned string
4428 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4429 * \returns the runtime version + build date in string format.
4432 mono_get_runtime_build_info (void)
4434 if (mono_build_date)
4435 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4437 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4441 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4443 GHashTable *assemblies = (GHashTable*)user_data;
4444 MonoImage *image = mono_assembly_get_image (ass);
4445 MonoMethod *method, *invoke;
4448 if (g_hash_table_lookup (assemblies, ass))
4451 g_hash_table_insert (assemblies, ass, ass);
4453 if (mini_verbose > 0)
4454 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4456 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4459 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4461 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4464 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4466 if (method->is_generic || mono_class_is_gtd (method->klass))
4470 if (mini_verbose > 1) {
4471 char * desc = mono_method_full_name (method, TRUE);
4472 g_print ("Compiling %d %s\n", count, desc);
4475 mono_compile_method_checked (method, &error);
4476 if (!is_ok (&error)) {
4477 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4480 if (strcmp (method->name, "Finalize") == 0) {
4481 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4482 mono_compile_method_checked (invoke, &error);
4483 mono_error_assert_ok (&error);
4485 #ifndef DISABLE_REMOTING
4486 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4487 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4488 mono_compile_method_checked (invoke, &error);
4489 mono_error_assert_ok (&error);
4494 /* Load and precompile referenced assemblies as well */
4495 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4496 mono_assembly_load_reference (image, i);
4497 if (image->references [i])
4498 mono_precompile_assembly (image->references [i], assemblies);
4502 void mono_precompile_assemblies ()
4504 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4506 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4508 g_hash_table_destroy (assemblies);
4513 * Have to export this for AOT.
4516 mono_personality (void)
4519 g_assert_not_reached ();
4523 static MonoBreakPolicy
4524 always_insert_breakpoint (MonoMethod *method)
4526 return MONO_BREAK_POLICY_ALWAYS;
4529 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4532 * mono_set_break_policy:
4533 * \param policy_callback the new callback function
4535 * Allow embedders to decide whether to actually obey breakpoint instructions
4536 * (both break IL instructions and \c Debugger.Break method calls), for example
4537 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4538 * untrusted or semi-trusted code.
4540 * \p policy_callback will be called every time a break point instruction needs to
4541 * be inserted with the method argument being the method that calls \c Debugger.Break
4542 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4543 * if it wants the breakpoint to not be effective in the given method.
4544 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4547 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4549 if (policy_callback)
4550 break_policy_func = policy_callback;
4552 break_policy_func = always_insert_breakpoint;
4556 mini_should_insert_breakpoint (MonoMethod *method)
4558 switch (break_policy_func (method)) {
4559 case MONO_BREAK_POLICY_ALWAYS:
4561 case MONO_BREAK_POLICY_NEVER:
4563 case MONO_BREAK_POLICY_ON_DBG:
4564 g_warning ("mdb no longer supported");
4567 g_warning ("Incorrect value returned from break policy callback");
4572 // Custom handlers currently only implemented by Windows.
4575 mono_runtime_install_custom_handlers (const char *handlers)
4581 mono_runtime_install_custom_handlers_usage (void)
4584 "Custom Handlers:\n"
4585 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4586 " separated list of available handlers to install.\n"
4588 "No handlers supported on current platform.\n");
4590 #endif /* HOST_WIN32 */