3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include "mono/metadata/profiler.h"
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/utils/mono-math.h>
55 #include <mono/utils/mono-compiler.h>
56 #include <mono/utils/mono-counters.h>
57 #include <mono/utils/mono-error-internals.h>
58 #include <mono/utils/mono-logger-internals.h>
59 #include <mono/utils/mono-mmap.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-tls.h>
62 #include <mono/utils/mono-hwcap.h>
63 #include <mono/utils/dtrace.h>
64 #include <mono/utils/mono-signal-handler.h>
65 #include <mono/utils/mono-threads.h>
66 #include <mono/utils/mono-threads-coop.h>
67 #include <mono/utils/checked-build.h>
68 #include <mono/utils/mono-proclib.h>
69 #include <mono/metadata/w32handle.h>
70 #include <mono/metadata/threadpool.h>
73 #include "seq-points.h"
80 #include "jit-icalls.h"
83 #include "mini-llvm.h"
84 #include "debugger-agent.h"
87 #ifdef MONO_ARCH_LLVM_SUPPORTED
89 #include "mini-llvm-cpp.h"
94 #ifdef ENABLE_INTERPRETER
95 #include "interp/interp.h"
98 static guint32 default_opt = 0;
99 static gboolean default_opt_set = FALSE;
101 gboolean mono_compile_aot = FALSE;
102 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
103 gboolean mono_aot_only = FALSE;
104 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
105 gboolean mono_llvm_only = FALSE;
106 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NONE;
108 const char *mono_build_date;
109 gboolean mono_do_signal_chaining;
110 gboolean mono_do_crash_chaining;
111 int mini_verbose = 0;
114 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
115 * it can load AOT code compiled by LLVM.
117 gboolean mono_use_llvm = FALSE;
119 gboolean mono_use_interpreter = FALSE;
121 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
122 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
123 static mono_mutex_t jit_mutex;
125 static MonoCodeManager *global_codeman;
127 MonoDebugOptions debug_options;
129 #ifdef VALGRIND_JIT_REGISTER_MAP
130 int valgrind_register;
132 GList* mono_aot_paths;
134 static gboolean mini_enable_profiler = FALSE;
135 static char* mini_profiler_options = NULL;
137 static GSList *tramp_infos;
139 static void register_icalls (void);
141 static gboolean mini_profiler_enabled (void) { return mini_enable_profiler; }
142 static const char* mini_profiler_get_options (void) { return mini_profiler_options; }
145 mono_running_on_valgrind (void)
148 if (RUNNING_ON_VALGRIND){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register = TRUE;
164 find_tramp (gpointer key, gpointer value, gpointer user_data)
166 FindTrampUserData *ud = (FindTrampUserData*)user_data;
169 ud->method = (MonoMethod*)key;
173 G_GNUC_UNUSED static char*
174 get_method_from_ip (void *ip)
180 MonoDomain *domain = mono_domain_get ();
181 MonoDebugSourceLocation *location;
182 FindTrampUserData user_data;
185 domain = mono_get_root_domain ();
187 ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
190 user_data.method = NULL;
191 mono_domain_lock (domain);
192 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
193 mono_domain_unlock (domain);
194 if (user_data.method) {
195 char *mname = mono_method_full_name (user_data.method, TRUE);
196 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
202 } else if (ji->is_trampoline) {
203 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
207 method = jinfo_get_method (ji);
208 method_name = mono_method_full_name (method, TRUE);
209 /* FIXME: unused ? */
210 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
212 res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
214 mono_debug_free_source_location (location);
215 g_free (method_name);
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
235 return get_method_from_ip (ip);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
250 mono_print_method_from_ip (void *ip)
254 MonoDebugSourceLocation *source;
255 MonoDomain *domain = mono_domain_get ();
256 MonoDomain *target_domain = mono_domain_get ();
257 FindTrampUserData user_data;
258 MonoGenericSharingContext*gsctx;
259 const char *shared_type;
262 domain = mono_get_root_domain ();
263 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
264 if (ji && ji->is_trampoline) {
265 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
273 user_data.method = NULL;
274 mono_domain_lock (domain);
275 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
276 mono_domain_unlock (domain);
278 if (user_data.method) {
279 char *mname = mono_method_full_name (user_data.method, TRUE);
280 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
285 g_print ("No method at %p\n", ip);
289 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
290 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
292 gsctx = mono_jit_info_get_generic_sharing_context (ji);
295 if (gsctx->is_gsharedvt)
296 shared_type = "gsharedvt ";
298 shared_type = "gshared ";
301 g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
304 g_print ("%s:%d\n", source->source_file, source->row);
307 mono_debug_free_source_location (source);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
321 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller->domain_neutral && !callee->domain_neutral)
331 cmethod = jinfo_get_method (caller);
332 if ((cmethod->klass == mono_defaults.appdomain_class) &&
333 (strstr (cmethod->name, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman) {
354 /* This can happen during startup */
355 global_codeman = mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman, size);
360 ptr = mono_code_manager_reserve (global_codeman, size);
366 /* The callback shouldn't take any locks */
368 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
371 mono_code_manager_foreach (global_codeman, func, user_data);
376 * mono_create_unwind_op:
378 * Create an unwind op with the given parameters.
381 mono_create_unwind_op (int when, int tag, int reg, int val)
383 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
394 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
396 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
399 res->has_context = context != NULL;
401 memcpy (&res->context, context, sizeof (MonoGenericContext));
407 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
409 return mono_jump_info_token_new2 (mp, image, token, NULL);
413 * mono_tramp_info_create:
415 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
416 * of JI, and UNWIND_OPS.
419 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
421 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
423 info->name = g_strdup ((char*)name);
425 info->code_size = code_size;
427 info->unwind_ops = unwind_ops;
433 mono_tramp_info_free (MonoTrampInfo *info)
438 mono_free_unwind_info (info->unwind_ops);
439 if (info->owns_uw_info)
440 g_free (info->uw_info);
445 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
449 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
450 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
451 ji->d.tramp_info = info;
452 ji->is_trampoline = TRUE;
454 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
456 mono_jit_info_table_add (domain, ji);
460 * mono_tramp_info_register:
462 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
467 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
475 domain = mono_get_root_domain ();
478 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
480 copy = g_new0 (MonoTrampInfo, 1);
482 copy->code = info->code;
483 copy->code_size = info->code_size;
484 copy->name = g_strdup (info->name);
486 if (info->unwind_ops) {
487 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
488 copy->owns_uw_info = TRUE;
490 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
491 guint8 *temp = copy->uw_info;
492 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
493 memcpy (copy->uw_info, temp, copy->uw_info_len);
497 /* Trampolines from aot have the unwind ops already encoded */
498 copy->uw_info = info->uw_info;
499 copy->uw_info_len = info->uw_info_len;
502 mono_save_trampoline_xdebug_info (info);
503 mono_lldb_save_trampoline_info (info);
505 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
507 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
511 /* If no root domain has been created yet, postpone the registration. */
513 tramp_infos = g_slist_prepend (tramp_infos, copy);
515 } else if (copy->uw_info) {
516 /* Only register trampolines that have unwind infos */
517 register_trampoline_jit_info (domain, copy);
520 if (mono_jit_map_is_enabled ())
521 mono_emit_jit_tramp (info->code, info->code_size, info->name);
523 mono_tramp_info_free (info);
527 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
529 mono_tramp_info_register_internal (info, domain, FALSE);
533 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
535 mono_tramp_info_register_internal (info, domain, TRUE);
539 mono_tramp_info_cleanup (void)
543 for (l = tramp_infos; l; l = l->next) {
544 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
546 mono_tramp_info_free (info);
548 g_slist_free (tramp_infos);
551 /* Register trampolines created before the root domain was created in the jit info tables */
553 register_trampolines (MonoDomain *domain)
557 for (l = tramp_infos; l; l = l->next) {
558 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
560 register_trampoline_jit_info (domain, info);
564 G_GNUC_UNUSED static void
570 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
571 * Set a breakpoint in break_count () to break the last time <x> is done.
573 G_GNUC_UNUSED gboolean
574 mono_debug_count (void)
576 static int count = 0, int_val = 0;
577 static gboolean inited, has_value = FALSE;
582 char *value = g_getenv ("COUNT");
584 int_val = atoi (value);
594 if (count == int_val)
604 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
609 gconstpointer trampoline;
610 MonoDomain *domain = mono_get_root_domain ();
611 gboolean check_exc = TRUE;
613 if (callinfo->wrapper)
614 return callinfo->wrapper;
616 if (callinfo->trampoline)
617 return callinfo->trampoline;
619 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
620 /* This icall is used to check for exceptions, so don't check in the wrapper */
623 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
624 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
628 trampoline = mono_compile_method_checked (wrapper, &error);
629 mono_error_assert_ok (&error);
632 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
633 mono_error_assert_ok (&error);
634 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
638 if (!callinfo->trampoline) {
639 mono_register_jit_icall_wrapper (callinfo, trampoline);
640 callinfo->trampoline = trampoline;
642 mono_loader_unlock ();
644 return callinfo->trampoline;
648 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
650 return mono_icall_get_wrapper_full (callinfo, FALSE);
653 static MonoJitDynamicMethodInfo*
654 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
656 MonoJitDynamicMethodInfo *res;
658 if (domain_jit_info (domain)->dynamic_code_hash)
659 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
666 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
669 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
671 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
673 g_assert (!sig->hasthis);
674 g_assert (sig->param_count < 3);
676 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
677 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
682 * For JIT icalls implemented in C.
683 * NAME should be the same as the name of the C function whose address is FUNC.
684 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
685 * can't throw exceptions.
688 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
690 MonoMethodSignature *sig;
693 sig = mono_create_icall_signature (sigstr);
697 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
701 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
703 MonoMethodSignature *sig;
706 sig = mono_create_icall_signature (sigstr);
710 mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
714 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
716 MonoMethodSignature *sig;
719 sig = mono_create_icall_signature (sigstr);
723 mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
727 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
729 MonoMethodSignature *sig;
732 sig = mono_create_icall_signature (sigstr);
736 mono_register_jit_icall (func, name, sig, save);
742 MonoJitTlsData *jit_tls;
744 if ((jit_tls = mono_tls_get_jit_tls ()))
747 * We do not assert here because this function can be called from
748 * mini-gc.c on a thread that has not executed any managed code, yet
749 * (the thread object allocation can trigger a collection).
755 mono_get_lmf_addr (void)
757 return (MonoLMF **)mono_tls_get_lmf_addr ();
761 mono_set_lmf (MonoLMF *lmf)
763 (*mono_get_lmf_addr ()) = lmf;
767 mono_get_jit_tls (void)
769 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
773 mono_set_jit_tls (MonoJitTlsData *jit_tls)
775 MonoThreadInfo *info;
777 mono_tls_set_jit_tls (jit_tls);
779 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
780 info = mono_thread_info_current ();
782 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
786 mono_set_lmf_addr (gpointer lmf_addr)
788 MonoThreadInfo *info;
790 mono_tls_set_lmf_addr (lmf_addr);
792 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
793 info = mono_thread_info_current ();
795 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
801 * Push an MonoLMFExt frame on the LMF stack.
804 mono_push_lmf (MonoLMFExt *ext)
806 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
809 lmf_addr = mono_get_lmf_addr ();
811 mono_arch_init_lmf_ext (ext, *lmf_addr);
813 mono_set_lmf ((MonoLMF*)ext);
822 * Pop the last frame from the LMF stack.
825 mono_pop_lmf (MonoLMF *lmf)
827 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
831 * mono_jit_thread_attach:
833 * Called by Xamarin.Mac and other products. Attach thread to runtime if
834 * needed and switch to @domain.
836 * @return the original domain which needs to be restored, or NULL.
839 mono_jit_thread_attach (MonoDomain *domain)
844 g_assert (!mono_threads_is_blocking_transition_enabled ());
847 /* Happens when called from AOTed code which is only used in the root domain. */
848 domain = mono_get_root_domain ();
853 attached = mono_tls_get_jit_tls () != NULL;
856 mono_thread_attach (domain);
859 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
862 orig = mono_domain_get ();
864 mono_domain_set (domain, TRUE);
866 return orig != domain ? orig : NULL;
870 * mono_jit_set_domain:
872 * Set domain to @domain if @domain is not null
875 mono_jit_set_domain (MonoDomain *domain)
877 g_assert (!mono_threads_is_blocking_transition_enabled ());
880 mono_domain_set (domain, TRUE);
885 * \param obj exception object
886 * Abort the thread, print exception information and stack trace
889 mono_thread_abort (MonoObject *obj)
891 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
893 /* handle_remove should be eventually called for this thread, too
896 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
897 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
900 mono_invoke_unhandled_exception_hook (obj);
905 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
907 MonoJitTlsData *jit_tls;
910 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
914 jit_tls = g_new0 (MonoJitTlsData, 1);
916 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
917 jit_tls->end_of_stack = stack_start;
919 mono_set_jit_tls (jit_tls);
921 lmf = g_new0 (MonoLMF, 1);
922 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
924 jit_tls->first_lmf = lmf;
926 mono_set_lmf_addr (&jit_tls->lmf);
930 #ifdef MONO_ARCH_HAVE_TLS_INIT
931 mono_arch_tls_init ();
934 mono_setup_altstack (jit_tls);
940 free_jit_tls_data (MonoJitTlsData *jit_tls)
942 mono_arch_free_jit_tls_data (jit_tls);
943 mono_free_altstack (jit_tls);
945 g_free (jit_tls->first_lmf);
950 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
952 MonoThreadInfo *thread;
953 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
954 thread = mono_thread_info_current_unchecked ();
956 thread->jit_data = jit_tls;
958 mono_arch_cpu_init ();
961 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
964 mono_thread_abort_dummy (MonoObject *obj)
966 if (mono_thread_attach_aborted_cb)
967 mono_thread_attach_aborted_cb (obj);
969 mono_thread_abort (obj);
973 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
975 MonoThreadInfo *thread;
976 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
977 thread = mono_thread_info_current_unchecked ();
979 thread->jit_data = jit_tls;
981 mono_arch_cpu_init ();
985 mini_thread_cleanup (MonoNativeThreadId tid)
987 MonoJitTlsData *jit_tls = NULL;
988 MonoThreadInfo *info;
990 info = mono_thread_info_current_unchecked ();
992 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
993 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
994 * not a trivial thing.
996 * The current offender is mono_thread_manage which cleanup threads from the outside.
998 if (info && mono_thread_info_get_tid (info) == tid) {
999 jit_tls = (MonoJitTlsData *)info->jit_data;
1000 info->jit_data = NULL;
1002 mono_set_jit_tls (NULL);
1004 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1005 if (mono_get_lmf ()) {
1006 mono_set_lmf (NULL);
1007 mono_set_lmf_addr (NULL);
1010 info = mono_thread_info_lookup (tid);
1012 jit_tls = (MonoJitTlsData *)info->jit_data;
1013 info->jit_data = NULL;
1015 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1019 free_jit_tls_data (jit_tls);
1023 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1025 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1029 ji->data.target = target;
1035 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1037 static const char* const patch_info_str[] = {
1038 #define PATCH_INFO(a,b) "" #a,
1039 #include "patch-info.h"
1044 mono_ji_type_to_string (MonoJumpInfoType type)
1046 return patch_info_str [type];
1050 mono_print_ji (const MonoJumpInfo *ji)
1053 case MONO_PATCH_INFO_RGCTX_FETCH: {
1054 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1056 printf ("[RGCTX_FETCH ");
1057 mono_print_ji (entry->data);
1058 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1061 case MONO_PATCH_INFO_METHODCONST: {
1062 char *s = mono_method_full_name (ji->data.method, TRUE);
1063 printf ("[METHODCONST - %s]", s);
1067 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1068 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1072 printf ("[%s]", patch_info_str [ji->type]);
1080 mono_ji_type_to_string (MonoJumpInfoType type)
1086 mono_print_ji (const MonoJumpInfo *ji)
1093 * mono_patch_info_dup_mp:
1095 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1098 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1100 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1101 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1103 switch (patch_info->type) {
1104 case MONO_PATCH_INFO_RVA:
1105 case MONO_PATCH_INFO_LDSTR:
1106 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1107 case MONO_PATCH_INFO_LDTOKEN:
1108 case MONO_PATCH_INFO_DECLSEC:
1109 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1110 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1112 case MONO_PATCH_INFO_SWITCH:
1113 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1114 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1115 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1116 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1118 case MONO_PATCH_INFO_RGCTX_FETCH:
1119 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1120 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1121 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1122 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1124 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1125 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1126 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1128 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1129 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1130 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1132 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1133 MonoGSharedVtMethodInfo *info;
1134 MonoGSharedVtMethodInfo *oinfo;
1137 oinfo = patch_info->data.gsharedvt_method;
1138 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1139 res->data.gsharedvt_method = info;
1140 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1141 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1142 for (i = 0; i < oinfo->num_entries; ++i) {
1143 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1144 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1146 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1148 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1149 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1152 case MONO_PATCH_INFO_VIRT_METHOD: {
1153 MonoJumpInfoVirtMethod *info;
1154 MonoJumpInfoVirtMethod *oinfo;
1156 oinfo = patch_info->data.virt_method;
1157 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1158 res->data.virt_method = info;
1159 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1170 mono_patch_info_hash (gconstpointer data)
1172 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1175 case MONO_PATCH_INFO_RVA:
1176 case MONO_PATCH_INFO_LDSTR:
1177 case MONO_PATCH_INFO_LDTOKEN:
1178 case MONO_PATCH_INFO_DECLSEC:
1179 return (ji->type << 8) | ji->data.token->token;
1180 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1181 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1182 case MONO_PATCH_INFO_INTERNAL_METHOD:
1183 return (ji->type << 8) | g_str_hash (ji->data.name);
1184 case MONO_PATCH_INFO_VTABLE:
1185 case MONO_PATCH_INFO_CLASS:
1186 case MONO_PATCH_INFO_IID:
1187 case MONO_PATCH_INFO_ADJUSTED_IID:
1188 case MONO_PATCH_INFO_METHODCONST:
1189 case MONO_PATCH_INFO_METHOD:
1190 case MONO_PATCH_INFO_METHOD_JUMP:
1191 case MONO_PATCH_INFO_IMAGE:
1192 case MONO_PATCH_INFO_ICALL_ADDR:
1193 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1194 case MONO_PATCH_INFO_FIELD:
1195 case MONO_PATCH_INFO_SFLDA:
1196 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1197 case MONO_PATCH_INFO_METHOD_RGCTX:
1198 case MONO_PATCH_INFO_SIGNATURE:
1199 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1200 case MONO_PATCH_INFO_AOT_JIT_INFO:
1201 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1202 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1203 return (ji->type << 8) | (gssize)ji->data.target;
1204 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1205 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1206 case MONO_PATCH_INFO_RGCTX_FETCH:
1207 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1208 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1210 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1212 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1213 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1214 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1215 case MONO_PATCH_INFO_GC_NURSERY_START:
1216 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1217 case MONO_PATCH_INFO_GOT_OFFSET:
1218 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1219 case MONO_PATCH_INFO_AOT_MODULE:
1220 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1221 return (ji->type << 8);
1222 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1223 return (ji->type << 8) | (ji->data.index);
1224 case MONO_PATCH_INFO_SWITCH:
1225 return (ji->type << 8) | ji->data.table->table_size;
1226 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1227 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1228 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1229 /* Hash on the selector name */
1230 return g_str_hash (ji->data.target);
1231 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1232 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1233 case MONO_PATCH_INFO_LDSTR_LIT:
1234 return g_str_hash (ji->data.target);
1235 case MONO_PATCH_INFO_VIRT_METHOD: {
1236 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1238 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1240 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1241 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1242 return (ji->type << 8) | g_str_hash (ji->data.target);
1243 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1244 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1246 printf ("info type: %d\n", ji->type);
1247 mono_print_ji (ji); printf ("\n");
1248 g_assert_not_reached ();
1254 * mono_patch_info_equal:
1256 * This might fail to recognize equivalent patches, i.e. floats, so its only
1257 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1261 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1263 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1264 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1266 if (ji1->type != ji2->type)
1269 switch (ji1->type) {
1270 case MONO_PATCH_INFO_RVA:
1271 case MONO_PATCH_INFO_LDSTR:
1272 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1273 case MONO_PATCH_INFO_LDTOKEN:
1274 case MONO_PATCH_INFO_DECLSEC:
1275 if ((ji1->data.token->image != ji2->data.token->image) ||
1276 (ji1->data.token->token != ji2->data.token->token) ||
1277 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1278 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1279 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1282 case MONO_PATCH_INFO_INTERNAL_METHOD:
1283 return g_str_equal (ji1->data.name, ji2->data.name);
1284 case MONO_PATCH_INFO_RGCTX_FETCH:
1285 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1286 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1287 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1289 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);
1291 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1292 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1293 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1295 return c1->sig == c2->sig && c1->method == c2->method;
1297 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1298 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1299 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1300 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;
1301 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1302 return ji1->data.index == ji2->data.index;
1303 case MONO_PATCH_INFO_VIRT_METHOD:
1304 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1305 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1306 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1307 if (ji1->data.target == ji2->data.target)
1309 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1310 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1311 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1313 if (ji1->data.target != ji2->data.target)
1322 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1324 unsigned char *ip = patch_info->ip.i + code;
1325 gconstpointer target = NULL;
1329 switch (patch_info->type) {
1330 case MONO_PATCH_INFO_BB:
1332 * FIXME: This could be hit for methods without a prolog. Should use -1
1333 * but too much code depends on a 0 initial value.
1335 //g_assert (patch_info->data.bb->native_offset);
1336 target = patch_info->data.bb->native_offset + code;
1338 case MONO_PATCH_INFO_ABS:
1339 target = patch_info->data.target;
1341 case MONO_PATCH_INFO_LABEL:
1342 target = patch_info->data.inst->inst_c0 + code;
1344 case MONO_PATCH_INFO_IP:
1347 case MONO_PATCH_INFO_METHOD_REL:
1348 target = code + patch_info->data.offset;
1350 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1351 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1353 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1354 g_assert_not_reached ();
1356 target = mono_icall_get_wrapper (mi);
1359 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1360 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1361 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1363 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1364 g_assert_not_reached ();
1369 case MONO_PATCH_INFO_METHOD_JUMP:
1370 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1371 if (!mono_error_ok (error))
1374 case MONO_PATCH_INFO_METHOD:
1375 if (patch_info->data.method == method) {
1378 /* get the trampoline to the method from the domain */
1379 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1380 if (!mono_error_ok (error))
1384 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1387 mono_domain_lock (domain);
1388 if (!domain_jit_info (domain)->method_code_hash)
1389 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1390 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1392 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1393 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1395 mono_domain_unlock (domain);
1399 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1400 g_assert (mono_threads_is_coop_enabled ());
1401 target = (gpointer)&mono_polling_required;
1403 case MONO_PATCH_INFO_SWITCH: {
1404 gpointer *jump_table;
1406 if (method && method->dynamic) {
1407 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1409 if (mono_aot_only) {
1410 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1412 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1416 for (i = 0; i < patch_info->data.table->table_size; i++) {
1417 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1420 target = jump_table;
1423 case MONO_PATCH_INFO_METHODCONST:
1424 case MONO_PATCH_INFO_CLASS:
1425 case MONO_PATCH_INFO_IMAGE:
1426 case MONO_PATCH_INFO_FIELD:
1427 case MONO_PATCH_INFO_SIGNATURE:
1428 case MONO_PATCH_INFO_AOT_MODULE:
1429 target = patch_info->data.target;
1431 case MONO_PATCH_INFO_IID:
1432 mono_class_init (patch_info->data.klass);
1433 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1435 case MONO_PATCH_INFO_ADJUSTED_IID:
1436 mono_class_init (patch_info->data.klass);
1437 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1439 case MONO_PATCH_INFO_VTABLE:
1440 target = mono_class_vtable (domain, patch_info->data.klass);
1443 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1444 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1446 if (del_tramp->is_virtual)
1447 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1449 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1452 case MONO_PATCH_INFO_SFLDA: {
1453 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1455 if (mono_class_field_is_special_static (patch_info->data.field)) {
1456 gpointer addr = NULL;
1458 mono_domain_lock (domain);
1459 if (domain->special_static_fields)
1460 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1461 mono_domain_unlock (domain);
1467 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1468 /* Done by the generated code */
1472 if (!mono_runtime_class_init_full (vtable, error)) {
1477 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1480 case MONO_PATCH_INFO_RVA: {
1481 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1484 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1485 target = mono_image_rva_map (patch_info->data.token->image, rva);
1488 case MONO_PATCH_INFO_R4:
1489 case MONO_PATCH_INFO_R8:
1490 target = patch_info->data.target;
1492 case MONO_PATCH_INFO_EXC_NAME:
1493 target = patch_info->data.name;
1495 case MONO_PATCH_INFO_LDSTR:
1497 mono_ldstr_checked (domain, patch_info->data.token->image,
1498 mono_metadata_token_index (patch_info->data.token->token), error);
1500 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1502 MonoClass *handle_class;
1504 handle = mono_ldtoken_checked (patch_info->data.token->image,
1505 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1506 if (!mono_error_ok (error))
1508 mono_class_init (handle_class);
1509 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1511 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1512 if (!mono_error_ok (error))
1516 case MONO_PATCH_INFO_LDTOKEN: {
1518 MonoClass *handle_class;
1520 handle = mono_ldtoken_checked (patch_info->data.token->image,
1521 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1522 if (!mono_error_ok (error))
1523 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1524 mono_class_init (handle_class);
1529 case MONO_PATCH_INFO_DECLSEC:
1530 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1532 case MONO_PATCH_INFO_ICALL_ADDR:
1533 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1534 /* run_cctors == 0 -> AOT */
1535 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1536 const char *exc_class;
1537 const char *exc_arg;
1540 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1542 if (mono_aot_only) {
1543 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1546 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));
1552 target = mono_lookup_internal_call (patch_info->data.method);
1554 if (!target && run_cctors)
1555 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1558 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1559 target = mono_thread_interruption_request_flag ();
1561 case MONO_PATCH_INFO_METHOD_RGCTX: {
1562 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1565 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1568 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1569 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1571 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1574 case MONO_PATCH_INFO_BB_OVF:
1575 case MONO_PATCH_INFO_EXC_OVF:
1576 case MONO_PATCH_INFO_GOT_OFFSET:
1577 case MONO_PATCH_INFO_NONE:
1579 case MONO_PATCH_INFO_RGCTX_FETCH: {
1580 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1582 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1585 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1586 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1588 /* AOT, not needed */
1591 target = mono_arch_get_seq_point_info (domain, code);
1594 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1595 int card_table_shift_bits;
1596 gpointer card_table_mask;
1598 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1601 case MONO_PATCH_INFO_GC_NURSERY_START: {
1605 target = mono_gc_get_nursery (&shift_bits, &size);
1608 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1612 mono_gc_get_nursery (&shift_bits, &size);
1614 target = (gpointer)(mgreg_t)shift_bits;
1617 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1618 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1621 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1625 case MONO_PATCH_INFO_LDSTR_LIT: {
1629 len = strlen ((const char *)patch_info->data.target);
1630 s = (char *)mono_domain_alloc0 (domain, len + 1);
1631 memcpy (s, patch_info->data.target, len);
1636 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1637 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1639 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1640 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1642 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1643 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1645 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1646 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1652 g_assert_not_reached ();
1655 return (gpointer)target;
1659 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1661 MonoGenericInst *inst;
1664 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1666 if (context && context->class_inst) {
1667 inst = context->class_inst;
1668 for (i = 0; i < inst->type_argc; ++i) {
1669 MonoType *type = inst->type_argv [i];
1671 if (mini_is_gsharedvt_gparam (type))
1672 gsctx->is_gsharedvt = TRUE;
1675 if (context && context->method_inst) {
1676 inst = context->method_inst;
1678 for (i = 0; i < inst->type_argc; ++i) {
1679 MonoType *type = inst->type_argv [i];
1681 if (mini_is_gsharedvt_gparam (type))
1682 gsctx->is_gsharedvt = TRUE;
1688 * LOCKING: Acquires the jit code hash lock.
1691 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1694 static gboolean inited = FALSE;
1695 static int lookups = 0;
1696 static int failed_lookups = 0;
1698 mono_domain_jit_code_hash_lock (domain);
1699 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1700 if (!ji && shared) {
1701 /* Try generic sharing */
1702 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1703 if (ji && !ji->has_generic_jit_info)
1706 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1707 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1715 mono_domain_jit_code_hash_unlock (domain);
1721 lookup_method (MonoDomain *domain, MonoMethod *method)
1726 ji = mini_lookup_method (domain, method, NULL);
1729 if (!mono_method_is_generic_sharable (method, FALSE))
1731 shared = mini_get_shared_method (method);
1732 ji = mini_lookup_method (domain, method, shared);
1739 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1741 return lookup_method (domain, method);
1745 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1750 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1751 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1753 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
1754 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1757 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
1758 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1761 mono_class_init (klass);
1766 static FILE* perf_map_file;
1769 mono_enable_jit_map (void)
1771 if (!perf_map_file) {
1773 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1775 perf_map_file = fopen (name, "w");
1780 mono_emit_jit_tramp (void *start, int size, const char *desc)
1783 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1787 mono_emit_jit_map (MonoJitInfo *jinfo)
1789 if (perf_map_file) {
1790 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1791 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1797 mono_jit_map_is_enabled (void)
1799 return perf_map_file != NULL;
1805 no_gsharedvt_in_wrapper (void)
1807 g_assert_not_reached ();
1813 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.
1814 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1815 Dependency management in this case is too complex to justify implementing it.
1817 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1820 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1821 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1822 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1823 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1828 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1829 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1830 int threads_waiting; /* Number of threads waiting on this job */
1831 gboolean has_cond; /* True if @cond was initialized */
1832 gboolean done; /* True if the method finished JIT'ing */
1833 MonoCoopCond cond; /* Cond sleeping threads wait one */
1834 } JitCompilationEntry;
1837 GPtrArray *in_flight_methods; //JitCompilationEntry*
1839 } JitCompilationData;
1841 static JitCompilationData compilation_data;
1842 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1845 mini_jit_init_job_control (void)
1847 mono_coop_mutex_init (&compilation_data.lock);
1848 compilation_data.in_flight_methods = g_ptr_array_new ();
1852 lock_compilation_data (void)
1854 mono_coop_mutex_lock (&compilation_data.lock);
1858 unlock_compilation_data (void)
1860 mono_coop_mutex_unlock (&compilation_data.lock);
1863 static JitCompilationEntry*
1864 find_method (MonoMethod *method, MonoDomain *domain)
1867 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1868 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1869 if (e->method == method && e->domain == domain)
1877 add_current_thread (MonoJitTlsData *jit_tls)
1879 ++jit_tls->active_jit_methods;
1883 unref_jit_entry (JitCompilationEntry *entry)
1886 if (entry->ref_count)
1888 if (entry->has_cond)
1889 mono_coop_cond_destroy (&entry->cond);
1894 * Returns true if this method waited successfully for another thread to JIT it
1897 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1899 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1900 JitCompilationEntry *entry;
1902 static gboolean inited;
1904 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1905 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1906 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1907 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1911 lock_compilation_data ();
1913 if (!(entry = find_method (method, domain))) {
1914 entry = g_new0 (JitCompilationEntry, 1);
1915 entry->method = method;
1916 entry->domain = domain;
1917 entry->compilation_count = entry->ref_count = 1;
1918 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1919 g_assert (find_method (method, domain) == entry);
1920 add_current_thread (jit_tls);
1922 unlock_compilation_data ();
1924 } else if (jit_tls->active_jit_methods > 0) {
1925 //We can't suspend the current thread if it's already JITing a method.
1926 //Dependency management is too compilated and we want to get rid of this anyways.
1927 ++entry->compilation_count;
1928 ++jit_methods_multiple;
1929 ++jit_tls->active_jit_methods;
1931 unlock_compilation_data ();
1934 ++jit_methods_waited;
1937 if (!entry->has_cond) {
1938 mono_coop_cond_init (&entry->cond);
1939 entry->has_cond = TRUE;
1943 ++entry->threads_waiting;
1945 g_assert (entry->has_cond);
1946 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1947 --entry->threads_waiting;
1950 unref_jit_entry (entry);
1951 unlock_compilation_data ();
1954 ++jit_spurious_wakeups;
1961 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1963 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1965 lock_compilation_data ();
1967 g_assert (jit_tls->active_jit_methods > 0);
1968 --jit_tls->active_jit_methods;
1970 JitCompilationEntry *entry = find_method (method, target_domain);
1971 g_assert (entry); // It would be weird to fail
1974 if (entry->threads_waiting) {
1975 g_assert (entry->has_cond);
1976 mono_coop_cond_broadcast (&entry->cond);
1979 if (--entry->compilation_count == 0) {
1980 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1981 unref_jit_entry (entry);
1984 unlock_compilation_data ();
1989 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1991 MonoDomain *target_domain, *domain = mono_domain_get ();
1993 gpointer code = NULL, p;
1995 MonoJitICallInfo *callinfo = NULL;
1996 WrapperInfo *winfo = NULL;
2000 #ifdef ENABLE_INTERPRETER
2001 if (mono_use_interpreter && !jit_only) {
2002 code = mono_interp_create_method_pointer (method, error);
2009 /* Should be handled by the caller */
2010 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2013 * ICALL wrappers are handled specially, since there is only one copy of them
2014 * shared by all appdomains.
2016 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2017 winfo = mono_marshal_get_wrapper_info (method);
2018 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2019 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2020 g_assert (callinfo);
2022 /* Must be domain neutral since there is only one copy */
2023 opt |= MONO_OPT_SHARED;
2025 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2026 opt &= ~MONO_OPT_SHARED;
2029 if (opt & MONO_OPT_SHARED)
2030 target_domain = mono_get_root_domain ();
2032 target_domain = domain;
2034 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2035 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2038 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2039 MonoGenericContext *ctx = NULL;
2040 if (method->is_inflated)
2041 ctx = mono_method_get_context (method);
2042 method = info->d.synchronized_inner.method;
2044 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2045 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2051 info = lookup_method (target_domain, method);
2053 /* We can't use a domain specific method in another domain */
2054 if (! ((domain != target_domain) && !info->domain_neutral)) {
2057 mono_jit_stats.methods_lookups++;
2058 vtable = mono_class_vtable_full (domain, method->klass, error);
2062 if (!mono_runtime_class_init_full (vtable, error))
2064 return mono_create_ftnptr (target_domain, info->code_start);
2068 #ifdef MONO_USE_AOT_COMPILER
2069 if (opt & MONO_OPT_AOT) {
2070 MonoDomain *domain = NULL;
2072 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2073 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2075 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
2076 /* AOT'd wrappers for interp must be owned by root domain */
2077 domain = mono_get_root_domain ();
2081 domain = mono_domain_get ();
2083 mono_class_init (method->klass);
2085 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2088 if (mono_gc_is_critical_method (method)) {
2090 * The suspend code needs to be able to lookup these methods by ip in async context,
2091 * so preload their jit info.
2093 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2098 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2099 * This is not a problem, since it will be initialized when the method is first
2100 * called by init_method ().
2102 if (!mono_llvm_only) {
2103 vtable = mono_class_vtable (domain, method->klass);
2105 if (!mono_runtime_class_init_full (vtable, error))
2114 if (!code && mono_llvm_only) {
2115 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2116 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2118 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2120 * These wrappers are only created for signatures which are in the program, but
2121 * sometimes we load methods too eagerly and have to create them even if they
2122 * will never be called.
2124 return no_gsharedvt_in_wrapper;
2130 if (wait_or_register_method_to_compile (method, target_domain))
2132 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2133 unregister_method_for_compile (method, target_domain);
2135 if (!mono_error_ok (error))
2138 if (!code && mono_llvm_only) {
2139 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2140 g_assert_not_reached ();
2146 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2150 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2152 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2156 p = mono_create_ftnptr (target_domain, code);
2159 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2160 mono_loader_lock ();
2162 if (!callinfo->wrapper) {
2163 callinfo->wrapper = p;
2164 mono_register_jit_icall_wrapper (callinfo, p);
2167 mono_loader_unlock ();
2174 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2178 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2183 * mono_jit_compile_method_jit_only:
2185 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2188 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2192 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2196 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2198 invalidated_delegate_trampoline (char *desc)
2200 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2201 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2207 * mono_jit_free_method:
2209 * Free all memory allocated by the JIT for METHOD.
2212 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2214 MonoJitDynamicMethodInfo *ji;
2215 gboolean destroy = TRUE;
2216 GHashTableIter iter;
2217 MonoJumpList *jlist;
2219 g_assert (method->dynamic);
2221 mono_domain_lock (domain);
2222 ji = mono_dynamic_code_hash_lookup (domain, method);
2223 mono_domain_unlock (domain);
2228 mono_debug_remove_method (method, domain);
2229 mono_lldb_remove_method (domain, method, ji);
2231 mono_domain_lock (domain);
2232 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2233 mono_domain_jit_code_hash_lock (domain);
2234 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2235 mono_domain_jit_code_hash_unlock (domain);
2236 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2238 /* requires the domain lock - took above */
2239 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2241 /* Remove jump targets in this method */
2242 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2243 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2244 GSList *tmp, *remove;
2247 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2248 guint8 *ip = (guint8 *)tmp->data;
2250 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2251 remove = g_slist_prepend (remove, tmp);
2253 for (tmp = remove; tmp; tmp = tmp->next) {
2254 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2256 g_slist_free (remove);
2258 mono_domain_unlock (domain);
2260 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2261 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2263 * Instead of freeing the code, change it to call an error routine
2264 * so people can fix their code.
2266 char *type = mono_type_full_name (&method->klass->byval_arg);
2267 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2270 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2276 * This needs to be done before freeing code_mp, since the code address is the
2277 * key in the table, so if we free the code_mp first, another thread can grab the
2278 * same code address and replace our entry in the table.
2280 mono_jit_info_table_remove (domain, ji->ji);
2283 mono_code_manager_destroy (ji->code_mp);
2288 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2290 MonoDomain *target_domain;
2293 if (default_opt & MONO_OPT_SHARED)
2294 target_domain = mono_get_root_domain ();
2296 target_domain = domain;
2298 info = lookup_method (target_domain, method);
2300 /* We can't use a domain specific method in another domain */
2301 if (! ((domain != target_domain) && !info->domain_neutral)) {
2302 mono_jit_stats.methods_lookups++;
2305 return info->code_start;
2314 static guint32 bisect_opt = 0;
2315 static GHashTable *bisect_methods_hash = NULL;
2318 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2321 char method_name [2048];
2324 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2325 g_assert (bisect_methods_hash);
2327 file = fopen (method_list_filename, "r");
2330 while (fgets (method_name, sizeof (method_name), file)) {
2331 size_t len = strlen (method_name);
2333 g_assert (method_name [len - 1] == '\n');
2334 method_name [len - 1] = 0;
2335 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2337 g_assert (feof (file));
2340 gboolean mono_do_single_method_regression = FALSE;
2341 guint32 mono_single_method_regression_opt = 0;
2342 MonoMethod *mono_current_single_method;
2343 GSList *mono_single_method_list;
2344 GHashTable *mono_single_method_hash;
2347 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2351 if (bisect_methods_hash) {
2352 char *name = mono_method_full_name (method, TRUE);
2353 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2356 return default_opt | bisect_opt;
2358 if (!mono_do_single_method_regression)
2360 if (!mono_current_single_method) {
2361 if (!mono_single_method_hash)
2362 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2363 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2364 g_hash_table_insert (mono_single_method_hash, method, method);
2365 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2369 if (method == mono_current_single_method)
2370 return mono_single_method_regression_opt;
2375 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2377 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2382 gpointer compiled_method;
2383 gpointer runtime_invoke;
2385 MonoDynCallInfo *dyn_call_info;
2386 MonoClass *ret_box_class;
2387 MonoMethodSignature *sig;
2388 gboolean gsharedvt_invoke;
2389 gpointer *wrapper_arg;
2390 } RuntimeInvokeInfo;
2392 static RuntimeInvokeInfo*
2393 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2396 RuntimeInvokeInfo *info;
2398 info = g_new0 (RuntimeInvokeInfo, 1);
2399 info->compiled_method = compiled_method;
2400 if (mono_llvm_only && method->string_ctor)
2401 info->sig = mono_marshal_get_string_ctor_signature (method);
2403 info->sig = mono_method_signature (method);
2405 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2406 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2407 if (!mono_error_ok (error))
2409 g_assert (info->vtable);
2411 MonoMethodSignature *sig = info->sig;
2415 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2416 * in full-aot mode, so we use a slower, but more generic wrapper if
2417 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2419 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2420 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2421 gboolean supported = TRUE;
2424 if (method->string_ctor)
2425 sig = mono_marshal_get_string_ctor_signature (method);
2427 for (i = 0; i < sig->param_count; ++i) {
2428 MonoType *t = sig->params [i];
2430 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2434 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2438 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2442 ret_type = sig->ret;
2443 switch (ret_type->type) {
2444 case MONO_TYPE_VOID:
2456 case MONO_TYPE_BOOLEAN:
2457 case MONO_TYPE_CHAR:
2460 info->ret_box_class = mono_class_from_mono_type (ret_type);
2463 info->ret_box_class = mono_defaults.int_class;
2465 case MONO_TYPE_STRING:
2466 case MONO_TYPE_CLASS:
2467 case MONO_TYPE_ARRAY:
2468 case MONO_TYPE_SZARRAY:
2469 case MONO_TYPE_OBJECT:
2471 case MONO_TYPE_GENERICINST:
2472 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2473 info->ret_box_class = mono_class_from_mono_type (ret_type);
2475 case MONO_TYPE_VALUETYPE:
2476 info->ret_box_class = mono_class_from_mono_type (ret_type);
2479 g_assert_not_reached ();
2483 if (!info->dyn_call_info) {
2484 if (mono_llvm_only) {
2485 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2486 g_assert_not_reached ();
2488 info->gsharedvt_invoke = TRUE;
2489 if (!callee_gsharedvt) {
2490 /* Invoke a gsharedvt out wrapper instead */
2491 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2492 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2494 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2495 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2497 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2498 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2499 g_free (wrapper_sig);
2501 info->compiled_method = mono_jit_compile_method (wrapper, error);
2502 if (!mono_error_ok (error)) {
2507 /* Gsharedvt methods can be invoked the same way */
2508 /* The out wrapper has the same signature as the compiled gsharedvt method */
2509 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2511 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2513 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2514 g_free (wrapper_sig);
2517 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2518 if (!mono_error_ok (error)) {
2528 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2530 MonoMethodSignature *sig = info->sig;
2531 MonoDomain *domain = mono_domain_get ();
2532 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2534 gpointer retval_ptr;
2535 guint8 retval [256];
2536 gpointer *param_refs;
2541 g_assert (info->gsharedvt_invoke);
2544 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2545 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2546 * signatures, so we only have to generate runtime invoke wrappers for these
2548 * This code also handles invocation of gsharedvt methods directly, no
2549 * out wrappers are used in that case.
2551 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2552 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2555 * The runtime invoke wrappers expects pointers to primitive types, so have to
2559 args [pindex ++] = &obj;
2560 if (sig->ret->type != MONO_TYPE_VOID) {
2561 retval_ptr = (gpointer)&retval;
2562 args [pindex ++] = &retval_ptr;
2564 for (i = 0; i < sig->param_count; ++i) {
2565 MonoType *t = sig->params [i];
2567 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2568 MonoClass *klass = mono_class_from_mono_type (t);
2569 guint8 *nullable_buf;
2572 size = mono_class_value_size (klass, NULL);
2573 nullable_buf = g_alloca (size);
2574 g_assert (nullable_buf);
2576 /* The argument pointed to by params [i] is either a boxed vtype or null */
2577 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2578 params [i] = nullable_buf;
2581 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2582 param_refs [i] = params [i];
2583 params [i] = &(param_refs [i]);
2585 args [pindex ++] = ¶ms [i];
2587 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2588 args [pindex ++] = &info->wrapper_arg;
2590 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2592 runtime_invoke (NULL, args, exc, info->compiled_method);
2596 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2597 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2599 return *(MonoObject**)retval;
2603 * mono_jit_runtime_invoke:
2604 * \param method: the method to invoke
2605 * \param obj: this pointer
2606 * \param params: array of parameter values.
2607 * \param exc: Set to the exception raised in the managed method.
2608 * \param error: error or caught exception object
2609 * If \p exc is NULL, \p error is thrown instead.
2610 * If coop is enabled, \p exc argument is ignored -
2611 * all exceptions are caught and propagated through \p error
2614 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2616 MonoMethod *invoke, *callee;
2617 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2618 MonoDomain *domain = mono_domain_get ();
2619 MonoJitDomainInfo *domain_info;
2620 RuntimeInvokeInfo *info, *info2;
2621 MonoJitInfo *ji = NULL;
2622 gboolean callee_gsharedvt = FALSE;
2624 #ifdef ENABLE_INTERPRETER
2625 if (mono_use_interpreter)
2626 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2631 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2632 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2636 domain_info = domain_jit_info (domain);
2638 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2641 if (mono_security_core_clr_enabled ()) {
2643 * This might be redundant since mono_class_vtable () already does this,
2644 * but keep it just in case for moonlight.
2646 mono_class_setup_vtable (method->klass);
2647 if (mono_class_has_failure (method->klass)) {
2648 mono_error_set_for_class_failure (error, method->klass);
2650 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2655 gpointer compiled_method;
2658 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2659 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2661 * Array Get/Set/Address methods. The JIT implements them using inline code
2662 * inside the runtime invoke wrappers, so no need to compile them.
2664 if (mono_aot_only) {
2666 * Call a wrapper, since the runtime invoke wrapper was not generated.
2668 MonoMethod *wrapper;
2670 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2671 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2679 compiled_method = mono_jit_compile_method (callee, error);
2680 if (!compiled_method) {
2681 g_assert (!mono_error_ok (error));
2685 if (mono_llvm_only) {
2686 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2687 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2688 if (callee_gsharedvt)
2689 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2692 if (!callee_gsharedvt)
2693 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2695 compiled_method = NULL;
2698 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2699 if (!mono_error_ok (error))
2702 mono_domain_lock (domain);
2703 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2704 mono_domain_unlock (domain);
2712 * We need this here because mono_marshal_get_runtime_invoke can place
2713 * the helper method in System.Object and not the target class.
2715 if (!mono_runtime_class_init_full (info->vtable, error)) {
2717 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2721 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2722 we always catch the exception and propagate it through the MonoError */
2723 gboolean catchExcInMonoError =
2724 (exc == NULL) && mono_threads_is_coop_enabled ();
2725 MonoObject *invoke_exc = NULL;
2726 if (catchExcInMonoError)
2729 /* The wrappers expect this to be initialized to NULL */
2733 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2734 if (info->dyn_call_info) {
2735 MonoMethodSignature *sig = mono_method_signature (method);
2737 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2740 guint8 retval [256];
2742 if (!dyn_runtime_invoke) {
2743 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2744 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2745 if (!mono_error_ok (error))
2749 /* Convert the arguments to the format expected by start_dyn_call () */
2750 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2753 args [pindex ++] = &obj;
2754 for (i = 0; i < sig->param_count; ++i) {
2755 MonoType *t = sig->params [i];
2758 args [pindex ++] = ¶ms [i];
2759 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2760 args [pindex ++] = ¶ms [i];
2762 args [pindex ++] = params [i];
2766 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2768 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2770 dyn_runtime_invoke (buf, exc, info->compiled_method);
2771 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2773 if (catchExcInMonoError && *exc != NULL) {
2774 mono_error_set_exception_instance (error, (MonoException*) *exc);
2778 if (info->ret_box_class)
2779 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2781 return *(MonoObject**)retval;
2787 if (mono_llvm_only) {
2788 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2792 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2794 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2796 if (catchExcInMonoError && *exc != NULL)
2797 mono_error_set_exception_instance (error, (MonoException*) *exc);
2806 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2809 * mini_llvmonly_initial_imt_tramp:
2811 * This function is called the first time a call is made through an IMT trampoline.
2812 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2815 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2817 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2822 mono_vtable_build_imt_slot (info->vtable, info->slot);
2824 imt = (gpointer*)info->vtable;
2825 imt -= MONO_IMT_SIZE;
2827 /* Return what the real IMT trampoline returns */
2828 ftndesc = imt [info->slot];
2831 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2832 /* Happens when the imt slot contains only a generic virtual method */
2834 return func ((gpointer *)ftndesc [1], imt_method);
2837 /* This is called indirectly through an imt slot. */
2839 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2843 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2844 while (arg [i] && arg [i] != imt_method)
2851 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2853 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2855 //g_assert (arg [0] == imt_method);
2860 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2862 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2863 if (arg [0] == imt_method)
2870 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2872 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2873 if (arg [0] == imt_method)
2875 else if (arg [2] == imt_method)
2882 * A version of the imt trampoline used for generic virtual/variant iface methods.
2883 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2884 * in the search table. The original JIT code had a 'fallback' trampoline it could
2885 * call, but we can't do that, so we just return NULL, and the compiled code
2889 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2893 while (arg [i] && arg [i] != imt_method)
2902 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2906 int i, index, real_count;
2907 gboolean virtual_generic = FALSE;
2910 * Create an array which is passed to the imt trampoline functions.
2911 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2915 for (i = 0; i < count; ++i) {
2916 MonoIMTCheckItem *item = imt_entries [i];
2918 if (item->is_equals)
2920 if (item->has_target_code)
2921 virtual_generic = TRUE;
2925 * Initialize all vtable entries reachable from this imt slot, so the compiled
2926 * code doesn't have to check it.
2928 for (i = 0; i < count; ++i) {
2929 MonoIMTCheckItem *item = imt_entries [i];
2932 if (!item->is_equals || item->has_target_code)
2934 vt_slot = item->value.vtable_slot;
2935 mono_init_vtable_slot (vtable, vt_slot);
2938 /* Save the entries into an array */
2939 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2941 for (i = 0; i < count; ++i) {
2942 MonoIMTCheckItem *item = imt_entries [i];
2944 if (!item->is_equals)
2947 g_assert (item->key);
2948 buf [(index * 2)] = item->key;
2949 if (item->has_target_code)
2950 buf [(index * 2) + 1] = item->value.target_code;
2952 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2955 buf [(index * 2)] = NULL;
2956 buf [(index * 2) + 1] = fail_tramp;
2959 * Return a function descriptor for a C function with 'buf' as its argument.
2960 * It will by called by JITted code.
2962 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2963 switch (real_count) {
2965 res [0] = mono_llvmonly_imt_tramp_1;
2968 res [0] = mono_llvmonly_imt_tramp_2;
2971 res [0] = mono_llvmonly_imt_tramp_3;
2974 res [0] = mono_llvmonly_imt_tramp;
2977 if (virtual_generic || fail_tramp)
2978 res [0] = mono_llvmonly_fallback_imt_tramp;
2984 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2986 MonoException *exc = NULL;
2988 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2989 MONO_SIG_HANDLER_GET_CONTEXT;
2991 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2993 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2995 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2996 if (mono_arch_is_int_overflow (ctx, info))
2998 * The spec says this throws ArithmeticException, but MS throws the derived
2999 * OverflowException.
3001 exc = mono_get_exception_overflow ();
3003 exc = mono_get_exception_divide_by_zero ();
3005 exc = mono_get_exception_divide_by_zero ();
3009 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3012 mono_handle_native_crash ("SIGFPE", ctx, info);
3013 if (mono_do_crash_chaining) {
3014 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3019 mono_arch_handle_exception (ctx, exc);
3022 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3025 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3027 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3028 MONO_SIG_HANDLER_GET_CONTEXT;
3030 if (mono_runtime_get_no_exec ())
3034 mono_handle_native_crash ("SIGILL", ctx, info);
3035 if (mono_do_crash_chaining) {
3036 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3040 g_assert_not_reached ();
3043 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3044 #define HAVE_SIG_INFO
3047 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3050 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3051 gpointer fault_addr = NULL;
3052 #ifdef HAVE_SIG_INFO
3053 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3057 MONO_SIG_HANDLER_GET_CONTEXT;
3059 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3060 if (mono_arch_is_single_step_event (info, ctx)) {
3061 mono_debugger_agent_single_step_event (ctx);
3063 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3064 mono_debugger_agent_breakpoint_hit (ctx);
3069 #if defined(HAVE_SIG_INFO)
3070 #if !defined(HOST_WIN32)
3071 fault_addr = info->si_addr;
3072 if (mono_aot_is_pagefault (info->si_addr)) {
3073 mono_aot_handle_pagefault (info->si_addr);
3078 /* The thread might no be registered with the runtime */
3079 if (!mono_domain_get () || !jit_tls) {
3080 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3082 mono_handle_native_crash ("SIGSEGV", ctx, info);
3083 if (mono_do_crash_chaining) {
3084 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3090 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3092 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3093 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3096 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3097 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3098 fault_addr = info->si_addr;
3099 if (fault_addr == NULL) {
3102 mono_sigctx_to_monoctx (ctx, &mctx);
3104 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3108 if (jit_tls->stack_size &&
3109 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3111 * The hard-guard page has been hit: there is not much we can do anymore
3112 * Print a hopefully clear message and abort.
3114 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3115 g_assert_not_reached ();
3117 /* The original handler might not like that it is executed on an altstack... */
3118 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3121 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3126 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3129 mono_handle_native_crash ("SIGSEGV", ctx, info);
3131 if (mono_do_crash_chaining) {
3132 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3137 mono_arch_handle_exception (ctx, NULL);
3141 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3144 MONO_SIG_HANDLER_GET_CONTEXT;
3146 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3148 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3150 mono_arch_handle_exception (ctx, exc);
3152 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3155 #ifndef DISABLE_REMOTING
3156 /* mono_jit_create_remoting_trampoline:
3157 * @method: pointer to the method info
3159 * Creates a trampoline which calls the remoting functions. This
3160 * is used in the vtable of transparent proxies.
3162 * Returns: a pointer to the newly created code
3165 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3168 guint8 *addr = NULL;
3172 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3173 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3177 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3178 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3179 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3182 addr = (guint8 *)mono_compile_method_checked (nm, error);
3183 return_val_if_nok (error, NULL);
3184 return mono_get_addr_from_ftnptr (addr);
3188 static G_GNUC_UNUSED void
3189 no_imt_trampoline (void)
3191 g_assert_not_reached ();
3194 static G_GNUC_UNUSED void
3195 no_vcall_trampoline (void)
3197 g_assert_not_reached ();
3200 static gpointer *vtable_trampolines;
3201 static int vtable_trampolines_size;
3204 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3206 int index = slot_index + MONO_IMT_SIZE;
3208 if (mono_llvm_only) {
3209 if (slot_index < 0) {
3210 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3211 // FIXME: Memory management
3212 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3213 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3216 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3218 mono_memory_barrier ();
3225 g_assert (slot_index >= - MONO_IMT_SIZE);
3226 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3228 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3232 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3233 while (new_size <= index)
3235 new_table = g_new0 (gpointer, new_size);
3237 if (vtable_trampolines)
3238 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3239 g_free (vtable_trampolines);
3240 mono_memory_barrier ();
3241 vtable_trampolines = (void **)new_table;
3242 vtable_trampolines_size = new_size;
3247 if (!vtable_trampolines [index])
3248 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3249 return vtable_trampolines [index];
3253 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3255 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3259 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3264 gpointer *imt = (gpointer*)vt;
3265 imt -= MONO_IMT_SIZE;
3267 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3271 is_callee_gsharedvt_variable (gpointer addr)
3274 gboolean callee_gsharedvt;
3276 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3278 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3279 if (callee_gsharedvt)
3280 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3281 return callee_gsharedvt;
3285 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3287 gpointer arg = NULL;
3289 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3290 arg = mini_method_get_rgctx (method);
3293 * Avoid adding gsharedvt in wrappers since they might not exist if
3294 * this delegate is called through a gsharedvt delegate invoke wrapper.
3295 * Instead, encode that the method is gsharedvt in del->extra_arg,
3296 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3298 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3299 g_assert ((((mgreg_t)arg) & 1) == 0);
3300 arg = (gpointer)(((mgreg_t)arg) | 1);
3306 mini_init_delegate (MonoDelegate *del)
3309 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3310 #ifdef ENABLE_INTERPRETER
3311 if (mono_use_interpreter)
3312 mono_interp_init_delegate (del);
3317 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3321 abs_offset = offset;
3323 abs_offset = - abs_offset;
3324 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3328 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3330 gboolean is_virtual_generic, is_interface, load_imt_reg;
3333 static guint8 **cache = NULL;
3334 static int cache_size = 0;
3339 if (MONO_TYPE_ISSTRUCT (sig->ret))
3342 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3343 is_interface = mono_class_is_interface (method->klass);
3344 load_imt_reg = is_virtual_generic || is_interface;
3347 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3349 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3351 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3352 g_assert (idx >= 0);
3354 /* Resize the cache to idx + 1 */
3355 if (cache_size < idx + 1) {
3357 if (cache_size < idx + 1) {
3359 int new_cache_size = idx + 1;
3361 new_cache = g_new0 (guint8*, new_cache_size);
3363 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3366 mono_memory_barrier ();
3368 cache_size = new_cache_size;
3376 /* FIXME Support more cases */
3377 if (mono_aot_only) {
3378 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3379 g_assert (cache [idx]);
3381 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3387 * mini_parse_debug_option:
3388 * @option: The option to parse.
3390 * Parses debug options for the mono runtime. The options are the same as for
3391 * the MONO_DEBUG environment variable.
3395 mini_parse_debug_option (const char *option)
3397 if (!strcmp (option, "handle-sigint"))
3398 debug_options.handle_sigint = TRUE;
3399 else if (!strcmp (option, "keep-delegates"))
3400 debug_options.keep_delegates = TRUE;
3401 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3402 debug_options.reverse_pinvoke_exceptions = TRUE;
3403 else if (!strcmp (option, "collect-pagefault-stats"))
3404 debug_options.collect_pagefault_stats = TRUE;
3405 else if (!strcmp (option, "break-on-unverified"))
3406 debug_options.break_on_unverified = TRUE;
3407 else if (!strcmp (option, "no-gdb-backtrace"))
3408 debug_options.no_gdb_backtrace = TRUE;
3409 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3410 debug_options.suspend_on_native_crash = TRUE;
3411 else if (!strcmp (option, "suspend-on-exception"))
3412 debug_options.suspend_on_exception = TRUE;
3413 else if (!strcmp (option, "suspend-on-unhandled"))
3414 debug_options.suspend_on_unhandled = TRUE;
3415 else if (!strcmp (option, "dont-free-domains"))
3416 mono_dont_free_domains = TRUE;
3417 else if (!strcmp (option, "dyn-runtime-invoke"))
3418 debug_options.dyn_runtime_invoke = TRUE;
3419 else if (!strcmp (option, "gdb"))
3420 debug_options.gdb = TRUE;
3421 else if (!strcmp (option, "lldb"))
3422 debug_options.lldb = TRUE;
3423 else if (!strcmp (option, "explicit-null-checks"))
3424 debug_options.explicit_null_checks = TRUE;
3425 else if (!strcmp (option, "gen-seq-points"))
3426 debug_options.gen_sdb_seq_points = TRUE;
3427 else if (!strcmp (option, "gen-compact-seq-points"))
3428 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3429 else if (!strcmp (option, "no-compact-seq-points"))
3430 debug_options.no_seq_points_compact_data = TRUE;
3431 else if (!strcmp (option, "single-imm-size"))
3432 debug_options.single_imm_size = TRUE;
3433 else if (!strcmp (option, "init-stacks"))
3434 debug_options.init_stacks = TRUE;
3435 else if (!strcmp (option, "casts"))
3436 debug_options.better_cast_details = TRUE;
3437 else if (!strcmp (option, "soft-breakpoints"))
3438 debug_options.soft_breakpoints = TRUE;
3439 else if (!strcmp (option, "check-pinvoke-callconv"))
3440 debug_options.check_pinvoke_callconv = TRUE;
3441 else if (!strcmp (option, "use-fallback-tls"))
3442 debug_options.use_fallback_tls = TRUE;
3443 else if (!strcmp (option, "debug-domain-unload"))
3444 mono_enable_debug_domain_unload (TRUE);
3445 else if (!strcmp (option, "partial-sharing"))
3446 mono_set_partial_sharing_supported (TRUE);
3447 else if (!strcmp (option, "align-small-structs"))
3448 mono_align_small_structs = TRUE;
3449 else if (!strcmp (option, "native-debugger-break"))
3450 debug_options.native_debugger_break = TRUE;
3451 else if (!strcmp (option, "disable_omit_fp"))
3452 debug_options.disable_omit_fp = TRUE;
3460 mini_parse_debug_options (void)
3462 char *options = g_getenv ("MONO_DEBUG");
3463 gchar **args, **ptr;
3468 args = g_strsplit (options, ",", -1);
3471 for (ptr = args; ptr && *ptr; ptr++) {
3472 const char *arg = *ptr;
3474 if (!mini_parse_debug_option (arg)) {
3475 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3476 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");
3485 mini_get_debug_options (void)
3487 return &debug_options;
3491 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3493 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3496 gpointer* desc = NULL;
3498 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3500 # if defined(__ppc64__) || defined(__powerpc64__)
3502 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3508 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3514 mini_get_addr_from_ftnptr (gpointer descr)
3516 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3517 return *(gpointer*)descr;
3524 register_jit_stats (void)
3526 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3527 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3528 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3529 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3530 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3531 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3532 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);
3533 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3534 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3535 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3536 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3537 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3538 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3539 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3540 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3541 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3542 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3543 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3544 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3545 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3546 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3547 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3548 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3549 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3550 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3551 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3552 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3553 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3554 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3555 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3556 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3557 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3558 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3559 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3560 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3561 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3562 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3563 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3564 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3565 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3566 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3567 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3568 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3569 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3570 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3571 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3572 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3573 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3574 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3575 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3576 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3577 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3578 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3579 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3580 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3581 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3582 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3583 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3584 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3585 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3586 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3589 static void runtime_invoke_info_free (gpointer value);
3592 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3594 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3595 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3597 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3601 class_method_pair_hash (gconstpointer data)
3603 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3605 return (gsize)pair->klass ^ (gsize)pair->method;
3609 mini_create_jit_domain_info (MonoDomain *domain)
3611 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3613 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3614 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3615 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3616 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3617 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3618 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3619 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3620 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3621 mono_jit_code_hash_init (&info->interp_code_hash);
3623 domain->runtime_info = info;
3627 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3629 MonoJumpList *jlist = (MonoJumpList *)value;
3630 g_slist_free (jlist->list);
3634 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3636 GSList *list = (GSList *)value;
3637 g_slist_free (list);
3641 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3643 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3644 mono_code_manager_destroy (di->code_mp);
3649 runtime_invoke_info_free (gpointer value)
3651 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3653 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3654 if (info->dyn_call_info)
3655 mono_arch_dyn_call_free (info->dyn_call_info);
3661 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3663 g_slist_free (value);
3667 mini_free_jit_domain_info (MonoDomain *domain)
3669 MonoJitDomainInfo *info = domain_jit_info (domain);
3671 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3672 g_hash_table_destroy (info->jump_target_hash);
3673 if (info->jump_target_got_slot_hash) {
3674 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3675 g_hash_table_destroy (info->jump_target_got_slot_hash);
3677 if (info->dynamic_code_hash) {
3678 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3679 g_hash_table_destroy (info->dynamic_code_hash);
3681 if (info->method_code_hash)
3682 g_hash_table_destroy (info->method_code_hash);
3683 g_hash_table_destroy (info->jump_trampoline_hash);
3684 g_hash_table_destroy (info->jit_trampoline_hash);
3685 g_hash_table_destroy (info->delegate_trampoline_hash);
3686 if (info->static_rgctx_trampoline_hash)
3687 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3688 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3689 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3690 g_hash_table_destroy (info->seq_points);
3691 g_hash_table_destroy (info->arch_seq_points);
3692 if (info->agent_info)
3693 mono_debugger_agent_free_domain_info (domain);
3694 if (info->gsharedvt_arg_tramp_hash)
3695 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3696 if (info->llvm_jit_callees) {
3697 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3698 g_hash_table_destroy (info->llvm_jit_callees);
3700 mono_internal_hash_table_destroy (&info->interp_code_hash);
3702 mono_llvm_free_domain_info (domain);
3705 g_free (domain->runtime_info);
3706 domain->runtime_info = NULL;
3709 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3712 code_manager_chunk_new (void *chunk, int size)
3714 mono_arch_code_chunk_new (chunk, size);
3718 code_manager_chunk_destroy (void *chunk)
3720 mono_arch_code_chunk_destroy (chunk);
3727 llvm_init_inner (void)
3729 if (!mono_llvm_load (NULL))
3740 * Load and initialize LLVM support.
3741 * Return TRUE on success.
3744 mini_llvm_init (void)
3747 static gboolean llvm_inited;
3748 static gboolean init_result;
3750 mono_loader_lock_if_inited ();
3752 init_result = llvm_init_inner ();
3755 mono_loader_unlock_if_inited ();
3763 mini_profiler_enable_with_options (const char* profile_options)
3765 mini_enable_profiler = TRUE;
3766 mini_profiler_options = g_strdup (profile_options);
3770 mini_init (const char *filename, const char *runtime_version)
3774 MonoRuntimeCallbacks callbacks;
3775 MonoThreadInfoRuntimeCallbacks ticallbacks;
3776 MonoCodeManagerCallbacks code_manager_callbacks;
3778 MONO_VES_INIT_BEGIN ();
3780 CHECKED_MONO_INIT ();
3782 #if defined(__linux__)
3783 if (access ("/proc/self/maps", F_OK) != 0) {
3784 g_print ("Mono requires /proc to be mounted.\n");
3789 #ifdef ENABLE_INTERPRETER
3790 mono_interp_init ();
3793 mono_os_mutex_init_recursive (&jit_mutex);
3795 mono_cross_helpers_run ();
3797 mono_counters_init ();
3801 mini_jit_init_job_control ();
3803 /* Happens when using the embedding interface */
3804 if (!default_opt_set)
3805 default_opt = mono_parse_default_optimizations (NULL);
3807 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3809 mono_set_generic_sharing_vt_supported (TRUE);
3812 mono_set_generic_sharing_vt_supported (TRUE);
3815 mono_tls_init_runtime_keys ();
3817 if (!global_codeman)
3818 global_codeman = mono_code_manager_new ();
3820 memset (&callbacks, 0, sizeof (callbacks));
3821 callbacks.create_ftnptr = mini_create_ftnptr;
3822 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3823 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3824 callbacks.set_cast_details = mono_set_cast_details;
3825 callbacks.debug_log = mono_debugger_agent_debug_log;
3826 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3827 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3828 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3829 callbacks.imt_entry_inited = mini_imt_entry_inited;
3830 callbacks.init_delegate = mini_init_delegate;
3831 #define JIT_INVOKE_WORKS
3832 #ifdef JIT_INVOKE_WORKS
3833 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3835 #define JIT_TRAMPOLINES_WORK
3836 #ifdef JIT_TRAMPOLINES_WORK
3837 callbacks.compile_method = mono_jit_compile_method;
3838 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3839 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3840 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3841 callbacks.free_method = mono_jit_free_method;
3842 #ifndef DISABLE_REMOTING
3843 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3847 mono_install_callbacks (&callbacks);
3849 memset (&ticallbacks, 0, sizeof (ticallbacks));
3850 ticallbacks.setup_async_callback = mono_setup_async_callback;
3851 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3852 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3853 ticallbacks.thread_state_init = mono_thread_state_init;
3856 mono_w32handle_init ();
3859 mono_thread_info_runtime_init (&ticallbacks);
3861 if (g_hasenv ("MONO_DEBUG")) {
3862 mini_parse_debug_options ();
3865 mono_code_manager_init ();
3867 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3868 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3869 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3870 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3872 mono_code_manager_install_callbacks (&code_manager_callbacks);
3876 mono_arch_cpu_init ();
3880 mono_unwind_init ();
3882 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3883 mono_lldb_init ("");
3884 mono_dont_free_domains = TRUE;
3887 #ifdef XDEBUG_ENABLED
3888 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3890 mono_xdebug_init (mono_xdebug);
3891 g_free (mono_xdebug);
3892 /* So methods for multiple domains don't have the same address */
3893 mono_dont_free_domains = TRUE;
3894 mono_using_xdebug = TRUE;
3895 } else if (mini_get_debug_options ()->gdb) {
3896 mono_xdebug_init ((char*)"gdb");
3897 mono_dont_free_domains = TRUE;
3898 mono_using_xdebug = TRUE;
3903 if (mono_use_llvm) {
3904 if (!mono_llvm_load (NULL)) {
3905 mono_use_llvm = FALSE;
3906 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3913 mono_trampolines_init ();
3915 if (default_opt & MONO_OPT_AOT)
3918 mono_debugger_agent_init ();
3920 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3921 mono_set_generic_sharing_supported (TRUE);
3924 mono_thread_info_signals_init ();
3926 #ifndef MONO_CROSS_COMPILE
3927 mono_runtime_install_handlers ();
3929 mono_threads_install_cleanup (mini_thread_cleanup);
3931 #ifdef JIT_TRAMPOLINES_WORK
3932 mono_install_create_domain_hook (mini_create_jit_domain_info);
3933 mono_install_free_domain_hook (mini_free_jit_domain_info);
3935 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3936 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3937 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3939 if (mini_profiler_enabled ()) {
3940 mono_profiler_load (mini_profiler_get_options ());
3941 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3944 if (debug_options.collect_pagefault_stats)
3945 mono_aot_set_make_unreadable (TRUE);
3947 if (runtime_version)
3948 domain = mono_init_version (filename, runtime_version);
3950 domain = mono_init_from_assembly (filename, filename);
3952 if (mono_aot_only) {
3953 /* This helps catch code allocation requests */
3954 mono_code_manager_set_read_only (domain->code_mp);
3955 mono_marshal_use_aot_wrappers (TRUE);
3958 if (mono_llvm_only) {
3959 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3960 mono_set_always_build_imt_trampolines (TRUE);
3961 } else if (mono_aot_only) {
3962 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3964 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3967 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3968 mono_arch_finish_init ();
3972 /* This must come after mono_init () in the aot-only case */
3973 mono_exceptions_init ();
3975 /* This should come after mono_init () too */
3979 mono_create_helper_signatures ();
3982 register_jit_stats ();
3984 #define JIT_CALLS_WORK
3985 #ifdef JIT_CALLS_WORK
3986 /* Needs to be called here since register_jit_icall depends on it */
3987 mono_marshal_init ();
3989 mono_arch_register_lowlevel_calls ();
3993 mono_generic_sharing_init ();
3996 #ifdef MONO_ARCH_SIMD_INTRINSICS
3997 mono_simd_intrinsics_init ();
4000 mono_tasklets_init ();
4002 register_trampolines (domain);
4004 if (mono_compile_aot)
4006 * Avoid running managed code when AOT compiling, since the platform
4007 * might only support aot-only execution.
4009 mono_runtime_set_no_exec (TRUE);
4011 mono_mem_account_register_counters ();
4013 #define JIT_RUNTIME_WORKS
4014 #ifdef JIT_RUNTIME_WORKS
4015 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4016 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4017 mono_error_assert_ok (&error);
4018 mono_thread_attach (domain);
4021 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4022 mono_runtime_setup_stat_profiler ();
4024 mono_profiler_runtime_initialized ();
4026 MONO_VES_INIT_END ();
4032 register_icalls (void)
4034 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4035 ves_icall_get_frame_info);
4036 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4037 ves_icall_get_trace);
4038 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4039 mono_runtime_install_handlers);
4040 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4041 mono_runtime_cleanup_handlers);
4043 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4044 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4045 mono_debugger_agent_unhandled_exception);
4049 * It's important that we pass `TRUE` as the last argument here, as
4050 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4051 * *did* emit a wrapper, we'd be looking at infinite recursion since
4052 * the wrapper would call the icall which would call the wrapper and
4055 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4056 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4058 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4059 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4060 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4061 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4062 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4063 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4065 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4066 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4067 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4068 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4069 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4070 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4071 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4072 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4073 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4075 // FIXME: This is broken
4076 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4079 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4080 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4081 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4082 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4083 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4084 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4086 if (mono_threads_is_coop_enabled ())
4087 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4089 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4090 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4091 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4092 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4093 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4094 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4096 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4097 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4098 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4101 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4102 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4103 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4104 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4107 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4108 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4109 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4110 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4111 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4114 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4115 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4118 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4119 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4120 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4123 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4124 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4127 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4128 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4129 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4130 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4131 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4132 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4133 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4136 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4137 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4138 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4141 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4142 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);
4144 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4145 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4147 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4148 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4150 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4151 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);
4153 #ifdef MONO_ARCH_EMULATE_FREM
4154 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4155 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4158 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4159 if (mono_arch_is_soft_float ()) {
4160 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4161 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4162 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4163 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4164 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4165 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4166 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4167 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4168 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4169 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4170 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4171 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4173 #if SIZEOF_VOID_P == 4
4174 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4177 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4178 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4179 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4180 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4181 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4182 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4183 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4184 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4185 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4186 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4188 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4189 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4190 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4191 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4192 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4194 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4195 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4196 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4197 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4200 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4202 #ifdef COMPRESSED_INTERFACE_BITMAP
4203 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4206 #if SIZEOF_REGISTER == 4
4207 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4209 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4212 /* other jit icalls */
4213 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4214 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4215 "ptr ptr ptr", FALSE);
4216 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4217 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4218 "ptr ptr ptr ptr", FALSE);
4219 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4220 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4221 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4222 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4223 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4224 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4225 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4226 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4227 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4228 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4229 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4230 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4231 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4232 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4233 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4234 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4235 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4236 register_icall (mono_break, "mono_break", NULL, TRUE);
4237 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4238 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4239 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4240 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4241 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4242 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4243 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4244 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4245 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4246 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4247 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4249 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4250 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4252 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4253 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4254 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4255 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4256 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4258 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4260 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4261 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4262 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4263 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4265 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4266 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4267 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4268 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4269 /* This needs a wrapper so it can have a preserveall cconv */
4270 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4271 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4272 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4273 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4274 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4275 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4276 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4278 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4279 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4280 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4281 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4284 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4286 /* Register tls icalls */
4287 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4288 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4289 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4290 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4291 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4292 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4293 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4294 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4295 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4296 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4299 MonoJitStats mono_jit_stats = {0};
4302 print_jit_stats (void)
4304 if (mono_jit_stats.enabled) {
4305 g_print ("Mono Jit statistics\n");
4306 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4307 mono_jit_stats.max_ratio_method);
4308 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4309 mono_jit_stats.biggest_method);
4311 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4312 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4313 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4314 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4315 g_print ("Methods: %ld\n", mono_stats.method_count);
4316 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4317 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4318 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4320 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4321 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4322 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4324 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4325 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4326 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4327 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4329 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4330 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4331 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4332 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4333 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4334 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4335 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4336 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4338 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4339 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4340 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4342 g_free (mono_jit_stats.max_ratio_method);
4343 mono_jit_stats.max_ratio_method = NULL;
4344 g_free (mono_jit_stats.biggest_method);
4345 mono_jit_stats.biggest_method = NULL;
4350 mini_cleanup (MonoDomain *domain)
4352 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4353 mono_runtime_shutdown_stat_profiler ();
4356 cominterop_release_all_rcws ();
4359 #ifndef MONO_CROSS_COMPILE
4361 * mono_domain_finalize () needs to be called early since it needs the
4362 * execution engine still fully working (it may invoke managed finalizers).
4364 mono_domain_finalize (domain, 2000);
4367 /* This accesses metadata so needs to be called before runtime shutdown */
4370 #ifndef MONO_CROSS_COMPILE
4371 mono_runtime_cleanup (domain);
4374 mono_threadpool_cleanup ();
4376 mono_profiler_shutdown ();
4378 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4380 mono_icall_cleanup ();
4382 mono_runtime_cleanup_handlers ();
4384 #ifndef MONO_CROSS_COMPILE
4385 mono_domain_free (domain, TRUE);
4390 mono_llvm_cleanup ();
4393 mono_aot_cleanup ();
4395 mono_trampolines_cleanup ();
4397 mono_unwind_cleanup ();
4399 mono_code_manager_destroy (global_codeman);
4400 g_free (vtable_trampolines);
4402 mini_jit_cleanup ();
4404 mono_tramp_info_cleanup ();
4406 mono_arch_cleanup ();
4408 mono_generic_sharing_cleanup ();
4412 mono_trace_cleanup ();
4414 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4416 if (mono_inject_async_exc_method)
4417 mono_method_desc_free (mono_inject_async_exc_method);
4419 mono_tls_free_keys ();
4421 mono_os_mutex_destroy (&jit_mutex);
4423 mono_code_manager_cleanup ();
4426 mono_w32handle_cleanup ();
4431 mono_set_defaults (int verbose_level, guint32 opts)
4433 mini_verbose = verbose_level;
4434 mono_set_optimizations (opts);
4438 mono_disable_optimizations (guint32 opts)
4440 default_opt &= ~opts;
4444 mono_set_optimizations (guint32 opts)
4447 default_opt_set = TRUE;
4448 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4449 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4452 mono_set_generic_sharing_vt_supported (TRUE);
4457 mono_set_verbose_level (guint32 level)
4459 mini_verbose = level;
4463 * mono_get_runtime_build_info:
4464 * The returned string is owned by the caller. The returned string
4465 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4466 * \returns the runtime version + build date in string format.
4469 mono_get_runtime_build_info (void)
4471 if (mono_build_date)
4472 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4474 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4478 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4480 GHashTable *assemblies = (GHashTable*)user_data;
4481 MonoImage *image = mono_assembly_get_image (ass);
4482 MonoMethod *method, *invoke;
4485 if (g_hash_table_lookup (assemblies, ass))
4488 g_hash_table_insert (assemblies, ass, ass);
4490 if (mini_verbose > 0)
4491 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4493 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4496 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4498 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4501 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4503 if (method->is_generic || mono_class_is_gtd (method->klass))
4507 if (mini_verbose > 1) {
4508 char * desc = mono_method_full_name (method, TRUE);
4509 g_print ("Compiling %d %s\n", count, desc);
4512 mono_compile_method_checked (method, &error);
4513 if (!is_ok (&error)) {
4514 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4517 if (strcmp (method->name, "Finalize") == 0) {
4518 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4519 mono_compile_method_checked (invoke, &error);
4520 mono_error_assert_ok (&error);
4522 #ifndef DISABLE_REMOTING
4523 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4524 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4525 mono_compile_method_checked (invoke, &error);
4526 mono_error_assert_ok (&error);
4531 /* Load and precompile referenced assemblies as well */
4532 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4533 mono_assembly_load_reference (image, i);
4534 if (image->references [i])
4535 mono_precompile_assembly (image->references [i], assemblies);
4539 void mono_precompile_assemblies ()
4541 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4543 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4545 g_hash_table_destroy (assemblies);
4550 * Have to export this for AOT.
4553 mono_personality (void)
4556 g_assert_not_reached ();
4560 static MonoBreakPolicy
4561 always_insert_breakpoint (MonoMethod *method)
4563 return MONO_BREAK_POLICY_ALWAYS;
4566 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4569 * mono_set_break_policy:
4570 * \param policy_callback the new callback function
4572 * Allow embedders to decide whether to actually obey breakpoint instructions
4573 * (both break IL instructions and \c Debugger.Break method calls), for example
4574 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4575 * untrusted or semi-trusted code.
4577 * \p policy_callback will be called every time a break point instruction needs to
4578 * be inserted with the method argument being the method that calls \c Debugger.Break
4579 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4580 * if it wants the breakpoint to not be effective in the given method.
4581 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4584 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4586 if (policy_callback)
4587 break_policy_func = policy_callback;
4589 break_policy_func = always_insert_breakpoint;
4593 mini_should_insert_breakpoint (MonoMethod *method)
4595 switch (break_policy_func (method)) {
4596 case MONO_BREAK_POLICY_ALWAYS:
4598 case MONO_BREAK_POLICY_NEVER:
4600 case MONO_BREAK_POLICY_ON_DBG:
4601 g_warning ("mdb no longer supported");
4604 g_warning ("Incorrect value returned from break policy callback");
4609 // Custom handlers currently only implemented by Windows.
4612 mono_runtime_install_custom_handlers (const char *handlers)
4618 mono_runtime_install_custom_handlers_usage (void)
4621 "Custom Handlers:\n"
4622 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4623 " separated list of available handlers to install.\n"
4625 "No handlers supported on current platform.\n");
4627 #endif /* HOST_WIN32 */