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-private.h>
43 #include <mono/metadata/mono-config.h>
44 #include <mono/metadata/environment.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/threads-types.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/runtime.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/utils/mono-math.h>
54 #include <mono/utils/mono-compiler.h>
55 #include <mono/utils/mono-counters.h>
56 #include <mono/utils/mono-error-internals.h>
57 #include <mono/utils/mono-logger-internals.h>
58 #include <mono/utils/mono-mmap.h>
59 #include <mono/utils/mono-path.h>
60 #include <mono/utils/mono-tls.h>
61 #include <mono/utils/mono-hwcap.h>
62 #include <mono/utils/dtrace.h>
63 #include <mono/utils/mono-signal-handler.h>
64 #include <mono/utils/mono-threads.h>
65 #include <mono/utils/mono-threads-coop.h>
66 #include <mono/utils/checked-build.h>
67 #include <mono/utils/mono-compiler.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 GPtrArray *profile_options;
136 static GSList *tramp_infos;
138 static void register_icalls (void);
141 mono_running_on_valgrind (void)
144 if (RUNNING_ON_VALGRIND){
145 #ifdef VALGRIND_JIT_REGISTER_MAP
146 valgrind_register = TRUE;
160 find_tramp (gpointer key, gpointer value, gpointer user_data)
162 FindTrampUserData *ud = (FindTrampUserData*)user_data;
165 ud->method = (MonoMethod*)key;
169 G_GNUC_UNUSED static char*
170 get_method_from_ip (void *ip)
176 MonoDomain *domain = mono_domain_get ();
177 MonoDebugSourceLocation *location;
178 FindTrampUserData user_data;
181 domain = mono_get_root_domain ();
183 ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
186 user_data.method = NULL;
187 mono_domain_lock (domain);
188 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
189 mono_domain_unlock (domain);
190 if (user_data.method) {
191 char *mname = mono_method_full_name (user_data.method, TRUE);
192 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
198 } else if (ji->is_trampoline) {
199 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
203 method = jinfo_get_method (ji);
204 method_name = mono_method_full_name (method, TRUE);
205 /* FIXME: unused ? */
206 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
208 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);
210 mono_debug_free_source_location (location);
211 g_free (method_name);
218 * \param ip an instruction pointer address
220 * This method is used from a debugger to get the name of the
221 * method at address \p ip. This routine is typically invoked from
222 * a debugger like this:
224 * (gdb) print mono_pmip ($pc)
226 * \returns the name of the method at address \p ip.
231 return get_method_from_ip (ip);
235 * mono_print_method_from_ip:
236 * \param ip an instruction pointer address
238 * This method is used from a debugger to get the name of the
239 * method at address \p ip.
241 * This prints the name of the method at address \p ip in the standard
242 * output. Unlike \c mono_pmip which returns a string, this routine
243 * prints the value on the standard output.
246 mono_print_method_from_ip (void *ip)
250 MonoDebugSourceLocation *source;
251 MonoDomain *domain = mono_domain_get ();
252 MonoDomain *target_domain = mono_domain_get ();
253 FindTrampUserData user_data;
254 MonoGenericSharingContext*gsctx;
255 const char *shared_type;
258 domain = mono_get_root_domain ();
259 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
260 if (ji && ji->is_trampoline) {
261 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
263 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
269 user_data.method = NULL;
270 mono_domain_lock (domain);
271 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
272 mono_domain_unlock (domain);
274 if (user_data.method) {
275 char *mname = mono_method_full_name (user_data.method, TRUE);
276 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
281 g_print ("No method at %p\n", ip);
285 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
286 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
288 gsctx = mono_jit_info_get_generic_sharing_context (ji);
291 if (gsctx->is_gsharedvt)
292 shared_type = "gsharedvt ";
294 shared_type = "gshared ";
297 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);
300 g_print ("%s:%d\n", source->source_file, source->row);
303 mono_debug_free_source_location (source);
308 * mono_method_same_domain:
310 * Determine whenever two compiled methods are in the same domain, thus
311 * the address of the callee can be embedded in the caller.
313 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
317 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
321 * If the call was made from domain-neutral to domain-specific
322 * code, we can't patch the call site.
324 if (caller->domain_neutral && !callee->domain_neutral)
327 cmethod = jinfo_get_method (caller);
328 if ((cmethod->klass == mono_defaults.appdomain_class) &&
329 (strstr (cmethod->name, "InvokeInDomain"))) {
330 /* The InvokeInDomain methods change the current appdomain */
338 * mono_global_codeman_reserve:
340 * Allocate code memory from the global code manager.
342 void *mono_global_codeman_reserve (int size)
347 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
349 if (!global_codeman) {
350 /* This can happen during startup */
351 global_codeman = mono_code_manager_new ();
352 return mono_code_manager_reserve (global_codeman, size);
356 ptr = mono_code_manager_reserve (global_codeman, size);
362 /* The callback shouldn't take any locks */
364 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
367 mono_code_manager_foreach (global_codeman, func, user_data);
372 * mono_create_unwind_op:
374 * Create an unwind op with the given parameters.
377 mono_create_unwind_op (int when, int tag, int reg, int val)
379 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
390 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
392 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
395 res->has_context = context != NULL;
397 memcpy (&res->context, context, sizeof (MonoGenericContext));
403 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
405 return mono_jump_info_token_new2 (mp, image, token, NULL);
409 * mono_tramp_info_create:
411 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
412 * of JI, and UNWIND_OPS.
415 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
417 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
419 info->name = g_strdup ((char*)name);
421 info->code_size = code_size;
423 info->unwind_ops = unwind_ops;
429 mono_tramp_info_free (MonoTrampInfo *info)
434 mono_free_unwind_info (info->unwind_ops);
435 if (info->owns_uw_info)
436 g_free (info->uw_info);
441 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
445 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
446 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
447 ji->d.tramp_info = info;
448 ji->is_trampoline = TRUE;
450 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
452 mono_jit_info_table_add (domain, ji);
456 * mono_tramp_info_register:
458 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
463 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
471 domain = mono_get_root_domain ();
474 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
476 copy = g_new0 (MonoTrampInfo, 1);
478 copy->code = info->code;
479 copy->code_size = info->code_size;
480 copy->name = g_strdup (info->name);
482 if (info->unwind_ops) {
483 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
484 copy->owns_uw_info = TRUE;
486 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
487 guint8 *temp = copy->uw_info;
488 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
489 memcpy (copy->uw_info, temp, copy->uw_info_len);
493 /* Trampolines from aot have the unwind ops already encoded */
494 copy->uw_info = info->uw_info;
495 copy->uw_info_len = info->uw_info_len;
498 mono_save_trampoline_xdebug_info (info);
499 mono_lldb_save_trampoline_info (info);
501 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
503 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
507 /* If no root domain has been created yet, postpone the registration. */
509 tramp_infos = g_slist_prepend (tramp_infos, copy);
511 } else if (copy->uw_info) {
512 /* Only register trampolines that have unwind infos */
513 register_trampoline_jit_info (domain, copy);
516 if (mono_jit_map_is_enabled ())
517 mono_emit_jit_tramp (info->code, info->code_size, info->name);
519 mono_tramp_info_free (info);
523 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
525 mono_tramp_info_register_internal (info, domain, FALSE);
529 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
531 mono_tramp_info_register_internal (info, domain, TRUE);
535 mono_tramp_info_cleanup (void)
539 for (l = tramp_infos; l; l = l->next) {
540 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
542 mono_tramp_info_free (info);
544 g_slist_free (tramp_infos);
547 /* Register trampolines created before the root domain was created in the jit info tables */
549 register_trampolines (MonoDomain *domain)
553 for (l = tramp_infos; l; l = l->next) {
554 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
556 register_trampoline_jit_info (domain, info);
560 G_GNUC_UNUSED static void
566 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
567 * Set a breakpoint in break_count () to break the last time <x> is done.
569 G_GNUC_UNUSED gboolean
570 mono_debug_count (void)
572 static int count = 0, int_val = 0;
573 static gboolean inited, has_value = FALSE;
578 char *value = g_getenv ("COUNT");
580 int_val = atoi (value);
590 if (count == int_val)
600 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
605 gconstpointer trampoline;
606 MonoDomain *domain = mono_get_root_domain ();
607 gboolean check_exc = TRUE;
609 if (callinfo->wrapper)
610 return callinfo->wrapper;
612 if (callinfo->trampoline)
613 return callinfo->trampoline;
615 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
616 /* This icall is used to check for exceptions, so don't check in the wrapper */
619 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
620 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
624 trampoline = mono_compile_method_checked (wrapper, &error);
625 mono_error_assert_ok (&error);
628 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
629 mono_error_assert_ok (&error);
630 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
634 if (!callinfo->trampoline) {
635 mono_register_jit_icall_wrapper (callinfo, trampoline);
636 callinfo->trampoline = trampoline;
638 mono_loader_unlock ();
640 return callinfo->trampoline;
644 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
646 return mono_icall_get_wrapper_full (callinfo, FALSE);
649 static MonoJitDynamicMethodInfo*
650 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
652 MonoJitDynamicMethodInfo *res;
654 if (domain_jit_info (domain)->dynamic_code_hash)
655 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
662 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
665 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
667 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
669 g_assert (!sig->hasthis);
670 g_assert (sig->param_count < 3);
672 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
673 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
678 * For JIT icalls implemented in C.
679 * NAME should be the same as the name of the C function whose address is FUNC.
680 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
681 * can't throw exceptions.
684 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
686 MonoMethodSignature *sig;
689 sig = mono_create_icall_signature (sigstr);
693 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
697 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
699 MonoMethodSignature *sig;
702 sig = mono_create_icall_signature (sigstr);
706 mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
710 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
712 MonoMethodSignature *sig;
715 sig = mono_create_icall_signature (sigstr);
719 mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
723 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
725 MonoMethodSignature *sig;
728 sig = mono_create_icall_signature (sigstr);
732 mono_register_jit_icall (func, name, sig, save);
738 MonoJitTlsData *jit_tls;
740 if ((jit_tls = mono_tls_get_jit_tls ()))
743 * We do not assert here because this function can be called from
744 * mini-gc.c on a thread that has not executed any managed code, yet
745 * (the thread object allocation can trigger a collection).
751 mono_get_lmf_addr (void)
753 return (MonoLMF **)mono_tls_get_lmf_addr ();
757 mono_set_lmf (MonoLMF *lmf)
759 (*mono_get_lmf_addr ()) = lmf;
763 mono_get_jit_tls (void)
765 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
769 mono_set_jit_tls (MonoJitTlsData *jit_tls)
771 MonoThreadInfo *info;
773 mono_tls_set_jit_tls (jit_tls);
775 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
776 info = mono_thread_info_current ();
778 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
782 mono_set_lmf_addr (gpointer lmf_addr)
784 MonoThreadInfo *info;
786 mono_tls_set_lmf_addr (lmf_addr);
788 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
789 info = mono_thread_info_current ();
791 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
797 * Push an MonoLMFExt frame on the LMF stack.
800 mono_push_lmf (MonoLMFExt *ext)
802 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
805 lmf_addr = mono_get_lmf_addr ();
807 mono_arch_init_lmf_ext (ext, *lmf_addr);
809 mono_set_lmf ((MonoLMF*)ext);
818 * Pop the last frame from the LMF stack.
821 mono_pop_lmf (MonoLMF *lmf)
823 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
827 * mono_jit_thread_attach:
829 * Called by Xamarin.Mac and other products. Attach thread to runtime if
830 * needed and switch to @domain.
832 * @return the original domain which needs to be restored, or NULL.
835 mono_jit_thread_attach (MonoDomain *domain)
840 g_assert (!mono_threads_is_blocking_transition_enabled ());
843 /* Happens when called from AOTed code which is only used in the root domain. */
844 domain = mono_get_root_domain ();
849 attached = mono_tls_get_jit_tls () != NULL;
852 mono_thread_attach (domain);
855 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
858 orig = mono_domain_get ();
860 mono_domain_set (domain, TRUE);
862 return orig != domain ? orig : NULL;
866 * mono_jit_set_domain:
868 * Set domain to @domain if @domain is not null
871 mono_jit_set_domain (MonoDomain *domain)
873 g_assert (!mono_threads_is_blocking_transition_enabled ());
876 mono_domain_set (domain, TRUE);
881 * \param obj exception object
882 * Abort the thread, print exception information and stack trace
885 mono_thread_abort (MonoObject *obj)
887 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
889 /* handle_remove should be eventually called for this thread, too
892 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
893 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
896 mono_invoke_unhandled_exception_hook (obj);
901 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
903 MonoJitTlsData *jit_tls;
906 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
910 jit_tls = g_new0 (MonoJitTlsData, 1);
912 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
913 jit_tls->end_of_stack = stack_start;
915 mono_set_jit_tls (jit_tls);
917 lmf = g_new0 (MonoLMF, 1);
918 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
920 jit_tls->first_lmf = lmf;
922 mono_set_lmf_addr (&jit_tls->lmf);
926 #ifdef MONO_ARCH_HAVE_TLS_INIT
927 mono_arch_tls_init ();
930 mono_setup_altstack (jit_tls);
936 free_jit_tls_data (MonoJitTlsData *jit_tls)
938 mono_arch_free_jit_tls_data (jit_tls);
939 mono_free_altstack (jit_tls);
941 g_free (jit_tls->first_lmf);
946 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
948 MonoThreadInfo *thread;
949 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
950 thread = mono_thread_info_current_unchecked ();
952 thread->jit_data = jit_tls;
954 mono_arch_cpu_init ();
957 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
960 mono_thread_abort_dummy (MonoObject *obj)
962 if (mono_thread_attach_aborted_cb)
963 mono_thread_attach_aborted_cb (obj);
965 mono_thread_abort (obj);
969 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
971 MonoThreadInfo *thread;
972 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
973 thread = mono_thread_info_current_unchecked ();
975 thread->jit_data = jit_tls;
977 mono_arch_cpu_init ();
981 mini_thread_cleanup (MonoNativeThreadId tid)
983 MonoJitTlsData *jit_tls = NULL;
984 MonoThreadInfo *info;
986 info = mono_thread_info_current_unchecked ();
988 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
989 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
990 * not a trivial thing.
992 * The current offender is mono_thread_manage which cleanup threads from the outside.
994 if (info && mono_thread_info_get_tid (info) == tid) {
995 jit_tls = (MonoJitTlsData *)info->jit_data;
996 info->jit_data = NULL;
998 mono_set_jit_tls (NULL);
1000 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1001 if (mono_get_lmf ()) {
1002 mono_set_lmf (NULL);
1003 mono_set_lmf_addr (NULL);
1006 info = mono_thread_info_lookup (tid);
1008 jit_tls = (MonoJitTlsData *)info->jit_data;
1009 info->jit_data = NULL;
1011 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1015 free_jit_tls_data (jit_tls);
1019 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1021 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1025 ji->data.target = target;
1031 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1033 static const char* const patch_info_str[] = {
1034 #define PATCH_INFO(a,b) "" #a,
1035 #include "patch-info.h"
1040 mono_ji_type_to_string (MonoJumpInfoType type)
1042 return patch_info_str [type];
1046 mono_print_ji (const MonoJumpInfo *ji)
1049 case MONO_PATCH_INFO_RGCTX_FETCH: {
1050 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1052 printf ("[RGCTX_FETCH ");
1053 mono_print_ji (entry->data);
1054 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1057 case MONO_PATCH_INFO_METHODCONST: {
1058 char *s = mono_method_full_name (ji->data.method, TRUE);
1059 printf ("[METHODCONST - %s]", s);
1063 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1064 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1068 printf ("[%s]", patch_info_str [ji->type]);
1076 mono_ji_type_to_string (MonoJumpInfoType type)
1082 mono_print_ji (const MonoJumpInfo *ji)
1089 * mono_patch_info_dup_mp:
1091 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1094 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1096 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1097 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1099 switch (patch_info->type) {
1100 case MONO_PATCH_INFO_RVA:
1101 case MONO_PATCH_INFO_LDSTR:
1102 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1103 case MONO_PATCH_INFO_LDTOKEN:
1104 case MONO_PATCH_INFO_DECLSEC:
1105 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1106 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1108 case MONO_PATCH_INFO_SWITCH:
1109 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1110 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1111 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1112 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1114 case MONO_PATCH_INFO_RGCTX_FETCH:
1115 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1116 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1117 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1118 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1120 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1121 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1122 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1124 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1125 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1126 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1128 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1129 MonoGSharedVtMethodInfo *info;
1130 MonoGSharedVtMethodInfo *oinfo;
1133 oinfo = patch_info->data.gsharedvt_method;
1134 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1135 res->data.gsharedvt_method = info;
1136 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1137 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1138 for (i = 0; i < oinfo->num_entries; ++i) {
1139 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1140 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1142 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1144 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1145 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1148 case MONO_PATCH_INFO_VIRT_METHOD: {
1149 MonoJumpInfoVirtMethod *info;
1150 MonoJumpInfoVirtMethod *oinfo;
1152 oinfo = patch_info->data.virt_method;
1153 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1154 res->data.virt_method = info;
1155 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1166 mono_patch_info_hash (gconstpointer data)
1168 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1171 case MONO_PATCH_INFO_RVA:
1172 case MONO_PATCH_INFO_LDSTR:
1173 case MONO_PATCH_INFO_LDTOKEN:
1174 case MONO_PATCH_INFO_DECLSEC:
1175 return (ji->type << 8) | ji->data.token->token;
1176 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1177 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1178 case MONO_PATCH_INFO_INTERNAL_METHOD:
1179 return (ji->type << 8) | g_str_hash (ji->data.name);
1180 case MONO_PATCH_INFO_VTABLE:
1181 case MONO_PATCH_INFO_CLASS:
1182 case MONO_PATCH_INFO_IID:
1183 case MONO_PATCH_INFO_ADJUSTED_IID:
1184 case MONO_PATCH_INFO_METHODCONST:
1185 case MONO_PATCH_INFO_METHOD:
1186 case MONO_PATCH_INFO_METHOD_JUMP:
1187 case MONO_PATCH_INFO_IMAGE:
1188 case MONO_PATCH_INFO_ICALL_ADDR:
1189 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1190 case MONO_PATCH_INFO_FIELD:
1191 case MONO_PATCH_INFO_SFLDA:
1192 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1193 case MONO_PATCH_INFO_METHOD_RGCTX:
1194 case MONO_PATCH_INFO_SIGNATURE:
1195 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1196 case MONO_PATCH_INFO_AOT_JIT_INFO:
1197 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1198 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1199 return (ji->type << 8) | (gssize)ji->data.target;
1200 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1201 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1202 case MONO_PATCH_INFO_RGCTX_FETCH:
1203 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1204 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1206 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1208 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1209 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1210 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1211 case MONO_PATCH_INFO_GC_NURSERY_START:
1212 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1213 case MONO_PATCH_INFO_GOT_OFFSET:
1214 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1215 case MONO_PATCH_INFO_AOT_MODULE:
1216 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1217 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1218 return (ji->type << 8);
1219 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1220 return (ji->type << 8) | (ji->data.index);
1221 case MONO_PATCH_INFO_SWITCH:
1222 return (ji->type << 8) | ji->data.table->table_size;
1223 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1224 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1225 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1226 /* Hash on the selector name */
1227 return g_str_hash (ji->data.target);
1228 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1229 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1230 case MONO_PATCH_INFO_LDSTR_LIT:
1231 return g_str_hash (ji->data.target);
1232 case MONO_PATCH_INFO_VIRT_METHOD: {
1233 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1235 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1237 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1238 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1239 return (ji->type << 8) | g_str_hash (ji->data.target);
1240 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1241 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1243 printf ("info type: %d\n", ji->type);
1244 mono_print_ji (ji); printf ("\n");
1245 g_assert_not_reached ();
1251 * mono_patch_info_equal:
1253 * This might fail to recognize equivalent patches, i.e. floats, so its only
1254 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1258 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1260 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1261 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1263 if (ji1->type != ji2->type)
1266 switch (ji1->type) {
1267 case MONO_PATCH_INFO_RVA:
1268 case MONO_PATCH_INFO_LDSTR:
1269 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1270 case MONO_PATCH_INFO_LDTOKEN:
1271 case MONO_PATCH_INFO_DECLSEC:
1272 if ((ji1->data.token->image != ji2->data.token->image) ||
1273 (ji1->data.token->token != ji2->data.token->token) ||
1274 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1275 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1276 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1279 case MONO_PATCH_INFO_INTERNAL_METHOD:
1280 return g_str_equal (ji1->data.name, ji2->data.name);
1281 case MONO_PATCH_INFO_RGCTX_FETCH:
1282 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1283 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1284 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1286 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);
1288 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1289 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1290 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1292 return c1->sig == c2->sig && c1->method == c2->method;
1294 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1295 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1296 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1297 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;
1298 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1299 return ji1->data.index == ji2->data.index;
1300 case MONO_PATCH_INFO_VIRT_METHOD:
1301 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1302 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1303 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1304 if (ji1->data.target == ji2->data.target)
1306 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1307 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1308 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1310 if (ji1->data.target != ji2->data.target)
1319 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1321 unsigned char *ip = patch_info->ip.i + code;
1322 gconstpointer target = NULL;
1326 switch (patch_info->type) {
1327 case MONO_PATCH_INFO_BB:
1329 * FIXME: This could be hit for methods without a prolog. Should use -1
1330 * but too much code depends on a 0 initial value.
1332 //g_assert (patch_info->data.bb->native_offset);
1333 target = patch_info->data.bb->native_offset + code;
1335 case MONO_PATCH_INFO_ABS:
1336 target = patch_info->data.target;
1338 case MONO_PATCH_INFO_LABEL:
1339 target = patch_info->data.inst->inst_c0 + code;
1341 case MONO_PATCH_INFO_IP:
1344 case MONO_PATCH_INFO_METHOD_REL:
1345 target = code + patch_info->data.offset;
1347 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1348 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1350 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1351 g_assert_not_reached ();
1353 target = mono_icall_get_wrapper (mi);
1356 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1357 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1358 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1360 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1361 g_assert_not_reached ();
1366 case MONO_PATCH_INFO_METHOD_JUMP:
1367 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1368 if (!mono_error_ok (error))
1371 case MONO_PATCH_INFO_METHOD:
1372 if (patch_info->data.method == method) {
1375 /* get the trampoline to the method from the domain */
1376 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1377 if (!mono_error_ok (error))
1381 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1384 mono_domain_lock (domain);
1385 if (!domain_jit_info (domain)->method_code_hash)
1386 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1387 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1389 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1390 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1392 mono_domain_unlock (domain);
1396 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1397 g_assert (mono_threads_is_coop_enabled ());
1398 target = (gpointer)&mono_polling_required;
1400 case MONO_PATCH_INFO_SWITCH: {
1401 gpointer *jump_table;
1403 if (method && method->dynamic) {
1404 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1406 if (mono_aot_only) {
1407 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1409 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1413 for (i = 0; i < patch_info->data.table->table_size; i++) {
1414 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1417 target = jump_table;
1420 case MONO_PATCH_INFO_METHODCONST:
1421 case MONO_PATCH_INFO_CLASS:
1422 case MONO_PATCH_INFO_IMAGE:
1423 case MONO_PATCH_INFO_FIELD:
1424 case MONO_PATCH_INFO_SIGNATURE:
1425 case MONO_PATCH_INFO_AOT_MODULE:
1426 target = patch_info->data.target;
1428 case MONO_PATCH_INFO_IID:
1429 mono_class_init (patch_info->data.klass);
1430 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1432 case MONO_PATCH_INFO_ADJUSTED_IID:
1433 mono_class_init (patch_info->data.klass);
1434 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1436 case MONO_PATCH_INFO_VTABLE:
1437 target = mono_class_vtable (domain, patch_info->data.klass);
1440 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1441 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1443 if (del_tramp->is_virtual)
1444 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1446 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1449 case MONO_PATCH_INFO_SFLDA: {
1450 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1452 if (mono_class_field_is_special_static (patch_info->data.field)) {
1453 gpointer addr = NULL;
1455 mono_domain_lock (domain);
1456 if (domain->special_static_fields)
1457 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1458 mono_domain_unlock (domain);
1464 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1465 /* Done by the generated code */
1469 if (!mono_runtime_class_init_full (vtable, error)) {
1474 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1477 case MONO_PATCH_INFO_RVA: {
1478 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1481 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1482 target = mono_image_rva_map (patch_info->data.token->image, rva);
1485 case MONO_PATCH_INFO_R4:
1486 case MONO_PATCH_INFO_R8:
1487 target = patch_info->data.target;
1489 case MONO_PATCH_INFO_EXC_NAME:
1490 target = patch_info->data.name;
1492 case MONO_PATCH_INFO_LDSTR:
1494 mono_ldstr_checked (domain, patch_info->data.token->image,
1495 mono_metadata_token_index (patch_info->data.token->token), error);
1497 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1499 MonoClass *handle_class;
1501 handle = mono_ldtoken_checked (patch_info->data.token->image,
1502 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1503 if (!mono_error_ok (error))
1505 mono_class_init (handle_class);
1506 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1508 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1509 if (!mono_error_ok (error))
1513 case MONO_PATCH_INFO_LDTOKEN: {
1515 MonoClass *handle_class;
1517 handle = mono_ldtoken_checked (patch_info->data.token->image,
1518 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1519 if (!mono_error_ok (error))
1520 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1521 mono_class_init (handle_class);
1526 case MONO_PATCH_INFO_DECLSEC:
1527 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1529 case MONO_PATCH_INFO_ICALL_ADDR:
1530 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1531 /* run_cctors == 0 -> AOT */
1532 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1533 const char *exc_class;
1534 const char *exc_arg;
1537 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1539 if (mono_aot_only) {
1540 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1543 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));
1549 target = mono_lookup_internal_call (patch_info->data.method);
1551 if (!target && run_cctors)
1552 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1555 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1556 target = mono_thread_interruption_request_flag ();
1558 case MONO_PATCH_INFO_METHOD_RGCTX: {
1559 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1562 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1565 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1566 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1568 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1571 case MONO_PATCH_INFO_BB_OVF:
1572 case MONO_PATCH_INFO_EXC_OVF:
1573 case MONO_PATCH_INFO_GOT_OFFSET:
1574 case MONO_PATCH_INFO_NONE:
1576 case MONO_PATCH_INFO_RGCTX_FETCH: {
1577 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1579 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1582 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1583 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1585 /* AOT, not needed */
1588 target = mono_arch_get_seq_point_info (domain, code);
1591 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1592 int card_table_shift_bits;
1593 gpointer card_table_mask;
1595 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1598 case MONO_PATCH_INFO_GC_NURSERY_START: {
1602 target = mono_gc_get_nursery (&shift_bits, &size);
1605 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1609 mono_gc_get_nursery (&shift_bits, &size);
1611 target = (gpointer)(mgreg_t)shift_bits;
1614 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1615 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1618 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1622 case MONO_PATCH_INFO_LDSTR_LIT: {
1626 len = strlen ((const char *)patch_info->data.target);
1627 s = (char *)mono_domain_alloc0 (domain, len + 1);
1628 memcpy (s, patch_info->data.target, len);
1633 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1634 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1636 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1637 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1639 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1640 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1642 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1643 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1648 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1649 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1653 g_assert_not_reached ();
1656 return (gpointer)target;
1660 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1662 MonoGenericInst *inst;
1665 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1667 if (context && context->class_inst) {
1668 inst = context->class_inst;
1669 for (i = 0; i < inst->type_argc; ++i) {
1670 MonoType *type = inst->type_argv [i];
1672 if (mini_is_gsharedvt_gparam (type))
1673 gsctx->is_gsharedvt = TRUE;
1676 if (context && context->method_inst) {
1677 inst = context->method_inst;
1679 for (i = 0; i < inst->type_argc; ++i) {
1680 MonoType *type = inst->type_argv [i];
1682 if (mini_is_gsharedvt_gparam (type))
1683 gsctx->is_gsharedvt = TRUE;
1689 * LOCKING: Acquires the jit code hash lock.
1692 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1695 static gboolean inited = FALSE;
1696 static int lookups = 0;
1697 static int failed_lookups = 0;
1699 mono_domain_jit_code_hash_lock (domain);
1700 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1701 if (!ji && shared) {
1702 /* Try generic sharing */
1703 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1704 if (ji && !ji->has_generic_jit_info)
1707 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1708 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1716 mono_domain_jit_code_hash_unlock (domain);
1722 lookup_method (MonoDomain *domain, MonoMethod *method)
1727 ji = mini_lookup_method (domain, method, NULL);
1730 if (!mono_method_is_generic_sharable (method, FALSE))
1732 shared = mini_get_shared_method (method);
1733 ji = mini_lookup_method (domain, method, shared);
1740 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1745 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1746 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1748 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
1749 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1752 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
1753 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1756 mono_class_init (klass);
1761 static FILE* perf_map_file;
1764 mono_enable_jit_map (void)
1766 if (!perf_map_file) {
1768 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1770 perf_map_file = fopen (name, "w");
1775 mono_emit_jit_tramp (void *start, int size, const char *desc)
1778 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1782 mono_emit_jit_map (MonoJitInfo *jinfo)
1784 if (perf_map_file) {
1785 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1786 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1792 mono_jit_map_is_enabled (void)
1794 return perf_map_file != NULL;
1800 no_gsharedvt_in_wrapper (void)
1802 g_assert_not_reached ();
1808 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.
1809 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1810 Dependency management in this case is too complex to justify implementing it.
1812 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1815 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1816 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1817 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1818 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1823 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1824 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1825 int threads_waiting; /* Number of threads waiting on this job */
1826 gboolean has_cond; /* True if @cond was initialized */
1827 gboolean done; /* True if the method finished JIT'ing */
1828 MonoCoopCond cond; /* Cond sleeping threads wait one */
1829 } JitCompilationEntry;
1832 GPtrArray *in_flight_methods; //JitCompilationEntry*
1834 } JitCompilationData;
1836 static JitCompilationData compilation_data;
1837 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1840 mini_jit_init_job_control (void)
1842 mono_coop_mutex_init (&compilation_data.lock);
1843 compilation_data.in_flight_methods = g_ptr_array_new ();
1847 lock_compilation_data (void)
1849 mono_coop_mutex_lock (&compilation_data.lock);
1853 unlock_compilation_data (void)
1855 mono_coop_mutex_unlock (&compilation_data.lock);
1858 static JitCompilationEntry*
1859 find_method (MonoMethod *method, MonoDomain *domain)
1862 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1863 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1864 if (e->method == method && e->domain == domain)
1872 add_current_thread (MonoJitTlsData *jit_tls)
1874 ++jit_tls->active_jit_methods;
1878 unref_jit_entry (JitCompilationEntry *entry)
1881 if (entry->ref_count)
1883 if (entry->has_cond)
1884 mono_coop_cond_destroy (&entry->cond);
1889 * Returns true if this method waited successfully for another thread to JIT it
1892 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1894 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1895 JitCompilationEntry *entry;
1897 static gboolean inited;
1899 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1900 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1901 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1902 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1906 lock_compilation_data ();
1908 if (!(entry = find_method (method, domain))) {
1909 entry = g_new0 (JitCompilationEntry, 1);
1910 entry->method = method;
1911 entry->domain = domain;
1912 entry->compilation_count = entry->ref_count = 1;
1913 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1914 g_assert (find_method (method, domain) == entry);
1915 add_current_thread (jit_tls);
1917 unlock_compilation_data ();
1919 } else if (jit_tls->active_jit_methods > 0) {
1920 //We can't suspend the current thread if it's already JITing a method.
1921 //Dependency management is too compilated and we want to get rid of this anyways.
1922 ++entry->compilation_count;
1923 ++jit_methods_multiple;
1924 ++jit_tls->active_jit_methods;
1926 unlock_compilation_data ();
1929 ++jit_methods_waited;
1932 if (!entry->has_cond) {
1933 mono_coop_cond_init (&entry->cond);
1934 entry->has_cond = TRUE;
1938 ++entry->threads_waiting;
1940 g_assert (entry->has_cond);
1941 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1942 --entry->threads_waiting;
1945 unref_jit_entry (entry);
1946 unlock_compilation_data ();
1949 ++jit_spurious_wakeups;
1956 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1958 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1960 lock_compilation_data ();
1962 g_assert (jit_tls->active_jit_methods > 0);
1963 --jit_tls->active_jit_methods;
1965 JitCompilationEntry *entry = find_method (method, target_domain);
1966 g_assert (entry); // It would be weird to fail
1969 if (entry->threads_waiting) {
1970 g_assert (entry->has_cond);
1971 mono_coop_cond_broadcast (&entry->cond);
1974 if (--entry->compilation_count == 0) {
1975 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1976 unref_jit_entry (entry);
1979 unlock_compilation_data ();
1984 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1986 MonoDomain *target_domain, *domain = mono_domain_get ();
1988 gpointer code = NULL, p;
1990 MonoJitICallInfo *callinfo = NULL;
1991 WrapperInfo *winfo = NULL;
1995 #ifdef ENABLE_INTERPRETER
1996 if (mono_use_interpreter && !jit_only) {
1997 code = mono_interp_create_method_pointer (method, error);
2004 /* Should be handled by the caller */
2005 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2008 * ICALL wrappers are handled specially, since there is only one copy of them
2009 * shared by all appdomains.
2011 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2012 winfo = mono_marshal_get_wrapper_info (method);
2013 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2014 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2015 g_assert (callinfo);
2017 /* Must be domain neutral since there is only one copy */
2018 opt |= MONO_OPT_SHARED;
2020 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2021 opt &= ~MONO_OPT_SHARED;
2024 if (opt & MONO_OPT_SHARED)
2025 target_domain = mono_get_root_domain ();
2027 target_domain = domain;
2029 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2030 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2033 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2034 MonoGenericContext *ctx = NULL;
2035 if (method->is_inflated)
2036 ctx = mono_method_get_context (method);
2037 method = info->d.synchronized_inner.method;
2039 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2040 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2046 info = lookup_method (target_domain, method);
2048 /* We can't use a domain specific method in another domain */
2049 if (! ((domain != target_domain) && !info->domain_neutral)) {
2052 InterlockedIncrement (&mono_jit_stats.methods_lookups);
2053 vtable = mono_class_vtable_full (domain, method->klass, error);
2057 if (!mono_runtime_class_init_full (vtable, error))
2059 return mono_create_ftnptr (target_domain, info->code_start);
2063 #ifdef MONO_USE_AOT_COMPILER
2064 if (opt & MONO_OPT_AOT) {
2065 MonoDomain *domain = NULL;
2067 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2068 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2070 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
2071 /* AOT'd wrappers for interp must be owned by root domain */
2072 domain = mono_get_root_domain ();
2076 domain = mono_domain_get ();
2078 mono_class_init (method->klass);
2080 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2083 if (mono_gc_is_critical_method (method)) {
2085 * The suspend code needs to be able to lookup these methods by ip in async context,
2086 * so preload their jit info.
2088 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2093 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2094 * This is not a problem, since it will be initialized when the method is first
2095 * called by init_method ().
2097 if (!mono_llvm_only) {
2098 vtable = mono_class_vtable (domain, method->klass);
2100 if (!mono_runtime_class_init_full (vtable, error))
2109 if (!code && mono_llvm_only) {
2110 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2111 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2113 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2115 * These wrappers are only created for signatures which are in the program, but
2116 * sometimes we load methods too eagerly and have to create them even if they
2117 * will never be called.
2119 return no_gsharedvt_in_wrapper;
2125 if (wait_or_register_method_to_compile (method, target_domain))
2127 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2128 unregister_method_for_compile (method, target_domain);
2130 if (!mono_error_ok (error))
2133 if (!code && mono_llvm_only) {
2134 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2135 g_assert_not_reached ();
2141 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2145 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2147 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2151 p = mono_create_ftnptr (target_domain, code);
2154 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2155 mono_loader_lock ();
2157 if (!callinfo->wrapper) {
2158 callinfo->wrapper = p;
2159 mono_register_jit_icall_wrapper (callinfo, p);
2162 mono_loader_unlock ();
2169 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2173 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2178 * mono_jit_compile_method_jit_only:
2180 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2183 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2187 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2191 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2193 invalidated_delegate_trampoline (char *desc)
2195 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2196 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2202 * mono_jit_free_method:
2204 * Free all memory allocated by the JIT for METHOD.
2207 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2209 MonoJitDynamicMethodInfo *ji;
2210 gboolean destroy = TRUE;
2211 GHashTableIter iter;
2212 MonoJumpList *jlist;
2214 g_assert (method->dynamic);
2216 mono_domain_lock (domain);
2217 ji = mono_dynamic_code_hash_lookup (domain, method);
2218 mono_domain_unlock (domain);
2223 mono_debug_remove_method (method, domain);
2224 mono_lldb_remove_method (domain, method, ji);
2226 mono_domain_lock (domain);
2227 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2228 mono_domain_jit_code_hash_lock (domain);
2229 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2230 mono_domain_jit_code_hash_unlock (domain);
2231 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2233 /* requires the domain lock - took above */
2234 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2236 /* Remove jump targets in this method */
2237 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2238 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2239 GSList *tmp, *remove;
2242 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2243 guint8 *ip = (guint8 *)tmp->data;
2245 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2246 remove = g_slist_prepend (remove, tmp);
2248 for (tmp = remove; tmp; tmp = tmp->next) {
2249 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2251 g_slist_free (remove);
2253 mono_domain_unlock (domain);
2255 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2256 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2258 * Instead of freeing the code, change it to call an error routine
2259 * so people can fix their code.
2261 char *type = mono_type_full_name (&method->klass->byval_arg);
2262 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2265 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2271 * This needs to be done before freeing code_mp, since the code address is the
2272 * key in the table, so if we free the code_mp first, another thread can grab the
2273 * same code address and replace our entry in the table.
2275 mono_jit_info_table_remove (domain, ji->ji);
2278 mono_code_manager_destroy (ji->code_mp);
2283 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2285 MonoDomain *target_domain;
2288 if (default_opt & MONO_OPT_SHARED)
2289 target_domain = mono_get_root_domain ();
2291 target_domain = domain;
2293 info = lookup_method (target_domain, method);
2295 /* We can't use a domain specific method in another domain */
2296 if (! ((domain != target_domain) && !info->domain_neutral)) {
2297 InterlockedIncrement (&mono_jit_stats.methods_lookups);
2300 return info->code_start;
2309 static guint32 bisect_opt = 0;
2310 static GHashTable *bisect_methods_hash = NULL;
2313 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2316 char method_name [2048];
2319 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2320 g_assert (bisect_methods_hash);
2322 file = fopen (method_list_filename, "r");
2325 while (fgets (method_name, sizeof (method_name), file)) {
2326 size_t len = strlen (method_name);
2328 g_assert (method_name [len - 1] == '\n');
2329 method_name [len - 1] = 0;
2330 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2332 g_assert (feof (file));
2335 gboolean mono_do_single_method_regression = FALSE;
2336 guint32 mono_single_method_regression_opt = 0;
2337 MonoMethod *mono_current_single_method;
2338 GSList *mono_single_method_list;
2339 GHashTable *mono_single_method_hash;
2342 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2346 if (bisect_methods_hash) {
2347 char *name = mono_method_full_name (method, TRUE);
2348 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2351 return default_opt | bisect_opt;
2353 if (!mono_do_single_method_regression)
2355 if (!mono_current_single_method) {
2356 if (!mono_single_method_hash)
2357 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2358 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2359 g_hash_table_insert (mono_single_method_hash, method, method);
2360 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2364 if (method == mono_current_single_method)
2365 return mono_single_method_regression_opt;
2370 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2372 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2377 gpointer compiled_method;
2378 gpointer runtime_invoke;
2380 MonoDynCallInfo *dyn_call_info;
2381 MonoClass *ret_box_class;
2382 MonoMethodSignature *sig;
2383 gboolean gsharedvt_invoke;
2384 gpointer *wrapper_arg;
2385 } RuntimeInvokeInfo;
2387 static RuntimeInvokeInfo*
2388 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2391 RuntimeInvokeInfo *info;
2393 info = g_new0 (RuntimeInvokeInfo, 1);
2394 info->compiled_method = compiled_method;
2395 if (mono_llvm_only && method->string_ctor)
2396 info->sig = mono_marshal_get_string_ctor_signature (method);
2398 info->sig = mono_method_signature (method);
2400 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2401 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2402 if (!mono_error_ok (error))
2404 g_assert (info->vtable);
2406 MonoMethodSignature *sig = info->sig;
2410 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2411 * in full-aot mode, so we use a slower, but more generic wrapper if
2412 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2414 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2415 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2416 gboolean supported = TRUE;
2419 if (method->string_ctor)
2420 sig = mono_marshal_get_string_ctor_signature (method);
2422 for (i = 0; i < sig->param_count; ++i) {
2423 MonoType *t = sig->params [i];
2425 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2429 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2433 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2437 ret_type = sig->ret;
2438 switch (ret_type->type) {
2439 case MONO_TYPE_VOID:
2451 case MONO_TYPE_BOOLEAN:
2452 case MONO_TYPE_CHAR:
2455 info->ret_box_class = mono_class_from_mono_type (ret_type);
2458 info->ret_box_class = mono_defaults.int_class;
2460 case MONO_TYPE_STRING:
2461 case MONO_TYPE_CLASS:
2462 case MONO_TYPE_ARRAY:
2463 case MONO_TYPE_SZARRAY:
2464 case MONO_TYPE_OBJECT:
2466 case MONO_TYPE_GENERICINST:
2467 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2468 info->ret_box_class = mono_class_from_mono_type (ret_type);
2470 case MONO_TYPE_VALUETYPE:
2471 info->ret_box_class = mono_class_from_mono_type (ret_type);
2474 g_assert_not_reached ();
2478 if (!info->dyn_call_info) {
2479 if (mono_llvm_only) {
2480 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2481 g_assert_not_reached ();
2483 info->gsharedvt_invoke = TRUE;
2484 if (!callee_gsharedvt) {
2485 /* Invoke a gsharedvt out wrapper instead */
2486 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2487 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2489 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2490 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2492 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2493 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2494 g_free (wrapper_sig);
2496 info->compiled_method = mono_jit_compile_method (wrapper, error);
2497 if (!mono_error_ok (error)) {
2502 /* Gsharedvt methods can be invoked the same way */
2503 /* The out wrapper has the same signature as the compiled gsharedvt method */
2504 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2506 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2508 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2509 g_free (wrapper_sig);
2512 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2513 if (!mono_error_ok (error)) {
2523 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2525 MonoMethodSignature *sig = info->sig;
2526 MonoDomain *domain = mono_domain_get ();
2527 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2529 gpointer retval_ptr;
2530 guint8 retval [256];
2531 gpointer *param_refs;
2536 g_assert (info->gsharedvt_invoke);
2539 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2540 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2541 * signatures, so we only have to generate runtime invoke wrappers for these
2543 * This code also handles invocation of gsharedvt methods directly, no
2544 * out wrappers are used in that case.
2546 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2547 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2550 * The runtime invoke wrappers expects pointers to primitive types, so have to
2554 args [pindex ++] = &obj;
2555 if (sig->ret->type != MONO_TYPE_VOID) {
2556 retval_ptr = (gpointer)&retval;
2557 args [pindex ++] = &retval_ptr;
2559 for (i = 0; i < sig->param_count; ++i) {
2560 MonoType *t = sig->params [i];
2562 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2563 MonoClass *klass = mono_class_from_mono_type (t);
2564 guint8 *nullable_buf;
2567 size = mono_class_value_size (klass, NULL);
2568 nullable_buf = g_alloca (size);
2569 g_assert (nullable_buf);
2571 /* The argument pointed to by params [i] is either a boxed vtype or null */
2572 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2573 params [i] = nullable_buf;
2576 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2577 param_refs [i] = params [i];
2578 params [i] = &(param_refs [i]);
2580 args [pindex ++] = ¶ms [i];
2582 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2583 args [pindex ++] = &info->wrapper_arg;
2585 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2587 runtime_invoke (NULL, args, exc, info->compiled_method);
2591 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2592 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2594 return *(MonoObject**)retval;
2598 * mono_jit_runtime_invoke:
2599 * \param method: the method to invoke
2600 * \param obj: this pointer
2601 * \param params: array of parameter values.
2602 * \param exc: Set to the exception raised in the managed method.
2603 * \param error: error or caught exception object
2604 * If \p exc is NULL, \p error is thrown instead.
2605 * If coop is enabled, \p exc argument is ignored -
2606 * all exceptions are caught and propagated through \p error
2609 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2611 MonoMethod *invoke, *callee;
2612 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2613 MonoDomain *domain = mono_domain_get ();
2614 MonoJitDomainInfo *domain_info;
2615 RuntimeInvokeInfo *info, *info2;
2616 MonoJitInfo *ji = NULL;
2617 gboolean callee_gsharedvt = FALSE;
2619 #ifdef ENABLE_INTERPRETER
2620 if (mono_use_interpreter)
2621 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2628 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2629 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2633 domain_info = domain_jit_info (domain);
2635 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2638 if (mono_security_core_clr_enabled ()) {
2640 * This might be redundant since mono_class_vtable () already does this,
2641 * but keep it just in case for moonlight.
2643 mono_class_setup_vtable (method->klass);
2644 if (mono_class_has_failure (method->klass)) {
2645 mono_error_set_for_class_failure (error, method->klass);
2647 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2652 gpointer compiled_method;
2655 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2656 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2658 * Array Get/Set/Address methods. The JIT implements them using inline code
2659 * inside the runtime invoke wrappers, so no need to compile them.
2661 if (mono_aot_only) {
2663 * Call a wrapper, since the runtime invoke wrapper was not generated.
2665 MonoMethod *wrapper;
2667 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2668 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2676 compiled_method = mono_jit_compile_method (callee, error);
2677 if (!compiled_method) {
2678 g_assert (!mono_error_ok (error));
2682 if (mono_llvm_only) {
2683 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2684 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2685 if (callee_gsharedvt)
2686 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2689 if (!callee_gsharedvt)
2690 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2692 compiled_method = NULL;
2695 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2696 if (!mono_error_ok (error))
2699 mono_domain_lock (domain);
2700 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2701 mono_domain_unlock (domain);
2709 * We need this here because mono_marshal_get_runtime_invoke can place
2710 * the helper method in System.Object and not the target class.
2712 if (!mono_runtime_class_init_full (info->vtable, error)) {
2714 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2718 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2719 we always catch the exception and propagate it through the MonoError */
2720 gboolean catchExcInMonoError =
2721 (exc == NULL) && mono_threads_is_coop_enabled ();
2722 MonoObject *invoke_exc = NULL;
2723 if (catchExcInMonoError)
2726 /* The wrappers expect this to be initialized to NULL */
2730 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2731 if (info->dyn_call_info) {
2732 MonoMethodSignature *sig = mono_method_signature (method);
2734 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2737 guint8 retval [256];
2739 if (!dyn_runtime_invoke) {
2740 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2741 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2742 if (!mono_error_ok (error))
2746 /* Convert the arguments to the format expected by start_dyn_call () */
2747 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2750 args [pindex ++] = &obj;
2751 for (i = 0; i < sig->param_count; ++i) {
2752 MonoType *t = sig->params [i];
2755 args [pindex ++] = ¶ms [i];
2756 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2757 args [pindex ++] = ¶ms [i];
2759 args [pindex ++] = params [i];
2763 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2765 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2767 dyn_runtime_invoke (buf, exc, info->compiled_method);
2768 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2770 if (catchExcInMonoError && *exc != NULL) {
2771 mono_error_set_exception_instance (error, (MonoException*) *exc);
2775 if (info->ret_box_class)
2776 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2778 return *(MonoObject**)retval;
2784 if (mono_llvm_only) {
2785 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2789 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2791 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2793 if (catchExcInMonoError && *exc != NULL)
2794 mono_error_set_exception_instance (error, (MonoException*) *exc);
2803 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2806 * mini_llvmonly_initial_imt_tramp:
2808 * This function is called the first time a call is made through an IMT trampoline.
2809 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2812 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2814 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2819 mono_vtable_build_imt_slot (info->vtable, info->slot);
2821 imt = (gpointer*)info->vtable;
2822 imt -= MONO_IMT_SIZE;
2824 /* Return what the real IMT trampoline returns */
2825 ftndesc = imt [info->slot];
2828 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2829 /* Happens when the imt slot contains only a generic virtual method */
2831 return func ((gpointer *)ftndesc [1], imt_method);
2834 /* This is called indirectly through an imt slot. */
2836 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2840 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2841 while (arg [i] && arg [i] != imt_method)
2848 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2850 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2852 //g_assert (arg [0] == imt_method);
2857 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2859 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2860 if (arg [0] == imt_method)
2867 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2869 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2870 if (arg [0] == imt_method)
2872 else if (arg [2] == imt_method)
2879 * A version of the imt trampoline used for generic virtual/variant iface methods.
2880 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2881 * in the search table. The original JIT code had a 'fallback' trampoline it could
2882 * call, but we can't do that, so we just return NULL, and the compiled code
2886 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2890 while (arg [i] && arg [i] != imt_method)
2899 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2903 int i, index, real_count;
2904 gboolean virtual_generic = FALSE;
2907 * Create an array which is passed to the imt trampoline functions.
2908 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2912 for (i = 0; i < count; ++i) {
2913 MonoIMTCheckItem *item = imt_entries [i];
2915 if (item->is_equals)
2917 if (item->has_target_code)
2918 virtual_generic = TRUE;
2922 * Initialize all vtable entries reachable from this imt slot, so the compiled
2923 * code doesn't have to check it.
2925 for (i = 0; i < count; ++i) {
2926 MonoIMTCheckItem *item = imt_entries [i];
2929 if (!item->is_equals || item->has_target_code)
2931 vt_slot = item->value.vtable_slot;
2932 mono_init_vtable_slot (vtable, vt_slot);
2935 /* Save the entries into an array */
2936 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2938 for (i = 0; i < count; ++i) {
2939 MonoIMTCheckItem *item = imt_entries [i];
2941 if (!item->is_equals)
2944 g_assert (item->key);
2945 buf [(index * 2)] = item->key;
2946 if (item->has_target_code)
2947 buf [(index * 2) + 1] = item->value.target_code;
2949 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2952 buf [(index * 2)] = NULL;
2953 buf [(index * 2) + 1] = fail_tramp;
2956 * Return a function descriptor for a C function with 'buf' as its argument.
2957 * It will by called by JITted code.
2959 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2960 switch (real_count) {
2962 res [0] = mono_llvmonly_imt_tramp_1;
2965 res [0] = mono_llvmonly_imt_tramp_2;
2968 res [0] = mono_llvmonly_imt_tramp_3;
2971 res [0] = mono_llvmonly_imt_tramp;
2974 if (virtual_generic || fail_tramp)
2975 res [0] = mono_llvmonly_fallback_imt_tramp;
2981 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2983 MonoException *exc = NULL;
2985 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2986 MONO_SIG_HANDLER_GET_CONTEXT;
2988 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2990 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2992 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2993 if (mono_arch_is_int_overflow (ctx, info))
2995 * The spec says this throws ArithmeticException, but MS throws the derived
2996 * OverflowException.
2998 exc = mono_get_exception_overflow ();
3000 exc = mono_get_exception_divide_by_zero ();
3002 exc = mono_get_exception_divide_by_zero ();
3006 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3009 mono_handle_native_crash ("SIGFPE", ctx, info);
3010 if (mono_do_crash_chaining) {
3011 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3016 mono_arch_handle_exception (ctx, exc);
3019 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3022 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3024 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3025 MONO_SIG_HANDLER_GET_CONTEXT;
3027 if (mono_runtime_get_no_exec ())
3031 mono_handle_native_crash ("SIGILL", ctx, info);
3032 if (mono_do_crash_chaining) {
3033 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3037 g_assert_not_reached ();
3040 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3041 #define HAVE_SIG_INFO
3044 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3047 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3048 gpointer fault_addr = NULL;
3049 #ifdef HAVE_SIG_INFO
3050 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3054 MONO_SIG_HANDLER_GET_CONTEXT;
3056 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3057 if (mono_arch_is_single_step_event (info, ctx)) {
3058 mono_debugger_agent_single_step_event (ctx);
3060 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3061 mono_debugger_agent_breakpoint_hit (ctx);
3066 #if defined(HAVE_SIG_INFO)
3067 #if !defined(HOST_WIN32)
3068 fault_addr = info->si_addr;
3069 if (mono_aot_is_pagefault (info->si_addr)) {
3070 mono_aot_handle_pagefault (info->si_addr);
3075 /* The thread might no be registered with the runtime */
3076 if (!mono_domain_get () || !jit_tls) {
3077 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3079 mono_handle_native_crash ("SIGSEGV", ctx, info);
3080 if (mono_do_crash_chaining) {
3081 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3087 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3089 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3090 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3093 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3094 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3095 fault_addr = info->si_addr;
3096 if (fault_addr == NULL) {
3099 mono_sigctx_to_monoctx (ctx, &mctx);
3101 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3105 if (jit_tls->stack_size &&
3106 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3108 * The hard-guard page has been hit: there is not much we can do anymore
3109 * Print a hopefully clear message and abort.
3111 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3112 g_assert_not_reached ();
3114 /* The original handler might not like that it is executed on an altstack... */
3115 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3118 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3123 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3126 mono_handle_native_crash ("SIGSEGV", ctx, info);
3128 if (mono_do_crash_chaining) {
3129 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3134 mono_arch_handle_exception (ctx, NULL);
3138 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3141 MONO_SIG_HANDLER_GET_CONTEXT;
3143 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3145 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3147 mono_arch_handle_exception (ctx, exc);
3149 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3152 #ifndef DISABLE_REMOTING
3153 /* mono_jit_create_remoting_trampoline:
3154 * @method: pointer to the method info
3156 * Creates a trampoline which calls the remoting functions. This
3157 * is used in the vtable of transparent proxies.
3159 * Returns: a pointer to the newly created code
3162 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3165 guint8 *addr = NULL;
3169 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3170 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3174 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3175 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3176 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3179 addr = (guint8 *)mono_compile_method_checked (nm, error);
3180 return_val_if_nok (error, NULL);
3181 return mono_get_addr_from_ftnptr (addr);
3185 static G_GNUC_UNUSED void
3186 no_imt_trampoline (void)
3188 g_assert_not_reached ();
3191 static G_GNUC_UNUSED void
3192 no_vcall_trampoline (void)
3194 g_assert_not_reached ();
3197 static gpointer *vtable_trampolines;
3198 static int vtable_trampolines_size;
3201 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3203 int index = slot_index + MONO_IMT_SIZE;
3205 if (mono_llvm_only) {
3206 if (slot_index < 0) {
3207 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3208 // FIXME: Memory management
3209 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3210 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3213 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3215 mono_memory_barrier ();
3222 g_assert (slot_index >= - MONO_IMT_SIZE);
3223 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3225 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3229 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3230 while (new_size <= index)
3232 new_table = g_new0 (gpointer, new_size);
3234 if (vtable_trampolines)
3235 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3236 g_free (vtable_trampolines);
3237 mono_memory_barrier ();
3238 vtable_trampolines = (void **)new_table;
3239 vtable_trampolines_size = new_size;
3244 if (!vtable_trampolines [index])
3245 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3246 return vtable_trampolines [index];
3250 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3252 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3256 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3261 gpointer *imt = (gpointer*)vt;
3262 imt -= MONO_IMT_SIZE;
3264 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3268 is_callee_gsharedvt_variable (gpointer addr)
3271 gboolean callee_gsharedvt;
3273 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3275 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3276 if (callee_gsharedvt)
3277 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3278 return callee_gsharedvt;
3282 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3284 gpointer arg = NULL;
3286 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3287 arg = mini_method_get_rgctx (method);
3290 * Avoid adding gsharedvt in wrappers since they might not exist if
3291 * this delegate is called through a gsharedvt delegate invoke wrapper.
3292 * Instead, encode that the method is gsharedvt in del->extra_arg,
3293 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3295 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3296 g_assert ((((mgreg_t)arg) & 1) == 0);
3297 arg = (gpointer)(((mgreg_t)arg) | 1);
3303 mini_init_delegate (MonoDelegate *del)
3305 #ifdef ENABLE_INTERPRETER
3306 if (mono_use_interpreter)
3307 mono_interp_init_delegate (del);
3311 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3315 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3319 abs_offset = offset;
3321 abs_offset = - abs_offset;
3322 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3326 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3328 gboolean is_virtual_generic, is_interface, load_imt_reg;
3331 static guint8 **cache = NULL;
3332 static int cache_size = 0;
3337 if (MONO_TYPE_ISSTRUCT (sig->ret))
3340 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3341 is_interface = mono_class_is_interface (method->klass);
3342 load_imt_reg = is_virtual_generic || is_interface;
3345 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3347 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3349 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3350 g_assert (idx >= 0);
3352 /* Resize the cache to idx + 1 */
3353 if (cache_size < idx + 1) {
3355 if (cache_size < idx + 1) {
3357 int new_cache_size = idx + 1;
3359 new_cache = g_new0 (guint8*, new_cache_size);
3361 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3364 mono_memory_barrier ();
3366 cache_size = new_cache_size;
3374 /* FIXME Support more cases */
3375 if (mono_aot_only) {
3376 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3377 g_assert (cache [idx]);
3379 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3385 * mini_parse_debug_option:
3386 * @option: The option to parse.
3388 * Parses debug options for the mono runtime. The options are the same as for
3389 * the MONO_DEBUG environment variable.
3393 mini_parse_debug_option (const char *option)
3395 if (!strcmp (option, "handle-sigint"))
3396 debug_options.handle_sigint = TRUE;
3397 else if (!strcmp (option, "keep-delegates"))
3398 debug_options.keep_delegates = TRUE;
3399 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3400 debug_options.reverse_pinvoke_exceptions = TRUE;
3401 else if (!strcmp (option, "collect-pagefault-stats"))
3402 debug_options.collect_pagefault_stats = TRUE;
3403 else if (!strcmp (option, "break-on-unverified"))
3404 debug_options.break_on_unverified = TRUE;
3405 else if (!strcmp (option, "no-gdb-backtrace"))
3406 debug_options.no_gdb_backtrace = TRUE;
3407 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3408 debug_options.suspend_on_native_crash = TRUE;
3409 else if (!strcmp (option, "suspend-on-exception"))
3410 debug_options.suspend_on_exception = TRUE;
3411 else if (!strcmp (option, "suspend-on-unhandled"))
3412 debug_options.suspend_on_unhandled = TRUE;
3413 else if (!strcmp (option, "dont-free-domains"))
3414 mono_dont_free_domains = TRUE;
3415 else if (!strcmp (option, "dyn-runtime-invoke"))
3416 debug_options.dyn_runtime_invoke = TRUE;
3417 else if (!strcmp (option, "gdb"))
3418 debug_options.gdb = TRUE;
3419 else if (!strcmp (option, "lldb"))
3420 debug_options.lldb = TRUE;
3421 else if (!strcmp (option, "explicit-null-checks"))
3422 debug_options.explicit_null_checks = TRUE;
3423 else if (!strcmp (option, "gen-seq-points"))
3424 debug_options.gen_sdb_seq_points = TRUE;
3425 else if (!strcmp (option, "gen-compact-seq-points"))
3426 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3427 else if (!strcmp (option, "no-compact-seq-points"))
3428 debug_options.no_seq_points_compact_data = TRUE;
3429 else if (!strcmp (option, "single-imm-size"))
3430 debug_options.single_imm_size = TRUE;
3431 else if (!strcmp (option, "init-stacks"))
3432 debug_options.init_stacks = TRUE;
3433 else if (!strcmp (option, "casts"))
3434 debug_options.better_cast_details = TRUE;
3435 else if (!strcmp (option, "soft-breakpoints"))
3436 debug_options.soft_breakpoints = TRUE;
3437 else if (!strcmp (option, "check-pinvoke-callconv"))
3438 debug_options.check_pinvoke_callconv = TRUE;
3439 else if (!strcmp (option, "use-fallback-tls"))
3440 debug_options.use_fallback_tls = TRUE;
3441 else if (!strcmp (option, "debug-domain-unload"))
3442 mono_enable_debug_domain_unload (TRUE);
3443 else if (!strcmp (option, "partial-sharing"))
3444 mono_set_partial_sharing_supported (TRUE);
3445 else if (!strcmp (option, "align-small-structs"))
3446 mono_align_small_structs = TRUE;
3447 else if (!strcmp (option, "native-debugger-break"))
3448 debug_options.native_debugger_break = TRUE;
3449 else if (!strcmp (option, "disable_omit_fp"))
3450 debug_options.disable_omit_fp = TRUE;
3458 mini_parse_debug_options (void)
3460 char *options = g_getenv ("MONO_DEBUG");
3461 gchar **args, **ptr;
3466 args = g_strsplit (options, ",", -1);
3469 for (ptr = args; ptr && *ptr; ptr++) {
3470 const char *arg = *ptr;
3472 if (!mini_parse_debug_option (arg)) {
3473 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3474 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");
3483 mini_get_debug_options (void)
3485 return &debug_options;
3489 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3491 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3494 gpointer* desc = NULL;
3496 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3498 # if defined(__ppc64__) || defined(__powerpc64__)
3500 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3506 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3512 mini_get_addr_from_ftnptr (gpointer descr)
3514 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3515 return *(gpointer*)descr;
3522 register_jit_stats (void)
3524 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3525 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3526 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3527 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3528 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3529 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3530 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);
3531 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3532 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3533 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3534 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3535 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3536 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3537 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3538 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3539 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3540 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3541 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3542 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3543 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3544 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3545 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3546 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3547 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3548 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3549 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3550 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3551 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3552 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3553 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3554 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3555 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3556 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3557 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3558 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3559 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3560 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3561 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3562 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3563 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3564 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3565 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3566 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3567 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3568 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3569 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3570 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3571 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3572 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3573 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3574 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3575 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3576 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3577 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3578 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3579 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3580 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3581 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3582 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3583 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3584 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3587 static void runtime_invoke_info_free (gpointer value);
3590 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3592 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3593 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3595 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3599 class_method_pair_hash (gconstpointer data)
3601 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3603 return (gsize)pair->klass ^ (gsize)pair->method;
3607 mini_create_jit_domain_info (MonoDomain *domain)
3609 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3611 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3612 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3613 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3614 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3615 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3616 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3617 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3618 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3619 mono_jit_code_hash_init (&info->interp_code_hash);
3621 domain->runtime_info = info;
3625 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3627 MonoJumpList *jlist = (MonoJumpList *)value;
3628 g_slist_free (jlist->list);
3632 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3634 GSList *list = (GSList *)value;
3635 g_slist_free (list);
3639 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3641 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3642 mono_code_manager_destroy (di->code_mp);
3647 runtime_invoke_info_free (gpointer value)
3649 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3651 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3652 if (info->dyn_call_info)
3653 mono_arch_dyn_call_free (info->dyn_call_info);
3659 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3661 g_slist_free (value);
3665 mini_free_jit_domain_info (MonoDomain *domain)
3667 MonoJitDomainInfo *info = domain_jit_info (domain);
3669 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3670 g_hash_table_destroy (info->jump_target_hash);
3671 if (info->jump_target_got_slot_hash) {
3672 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3673 g_hash_table_destroy (info->jump_target_got_slot_hash);
3675 if (info->dynamic_code_hash) {
3676 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3677 g_hash_table_destroy (info->dynamic_code_hash);
3679 if (info->method_code_hash)
3680 g_hash_table_destroy (info->method_code_hash);
3681 g_hash_table_destroy (info->jump_trampoline_hash);
3682 g_hash_table_destroy (info->jit_trampoline_hash);
3683 g_hash_table_destroy (info->delegate_trampoline_hash);
3684 if (info->static_rgctx_trampoline_hash)
3685 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3686 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3687 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3688 g_hash_table_destroy (info->seq_points);
3689 g_hash_table_destroy (info->arch_seq_points);
3690 if (info->agent_info)
3691 mono_debugger_agent_free_domain_info (domain);
3692 if (info->gsharedvt_arg_tramp_hash)
3693 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3694 if (info->llvm_jit_callees) {
3695 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3696 g_hash_table_destroy (info->llvm_jit_callees);
3698 mono_internal_hash_table_destroy (&info->interp_code_hash);
3700 mono_llvm_free_domain_info (domain);
3703 g_free (domain->runtime_info);
3704 domain->runtime_info = NULL;
3707 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3710 code_manager_chunk_new (void *chunk, int size)
3712 mono_arch_code_chunk_new (chunk, size);
3716 code_manager_chunk_destroy (void *chunk)
3718 mono_arch_code_chunk_destroy (chunk);
3725 llvm_init_inner (void)
3727 if (!mono_llvm_load (NULL))
3738 * Load and initialize LLVM support.
3739 * Return TRUE on success.
3742 mini_llvm_init (void)
3745 static gboolean llvm_inited;
3746 static gboolean init_result;
3748 mono_loader_lock_if_inited ();
3750 init_result = llvm_init_inner ();
3753 mono_loader_unlock_if_inited ();
3761 mini_add_profiler_argument (const char *desc)
3763 if (!profile_options)
3764 profile_options = g_ptr_array_new ();
3766 g_ptr_array_add (profile_options, (gpointer) desc);
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 mono_profiler_state.context_enable = mini_profiler_context_enable;
3940 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
3941 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
3942 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
3943 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
3944 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
3946 if (profile_options)
3947 for (guint i = 0; i < profile_options->len; i++)
3948 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
3950 mono_profiler_started ();
3952 if (debug_options.collect_pagefault_stats)
3953 mono_aot_set_make_unreadable (TRUE);
3955 if (runtime_version)
3956 domain = mono_init_version (filename, runtime_version);
3958 domain = mono_init_from_assembly (filename, filename);
3960 if (mono_aot_only) {
3961 /* This helps catch code allocation requests */
3962 mono_code_manager_set_read_only (domain->code_mp);
3963 mono_marshal_use_aot_wrappers (TRUE);
3966 if (mono_llvm_only) {
3967 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3968 mono_set_always_build_imt_trampolines (TRUE);
3969 } else if (mono_aot_only) {
3970 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3972 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3975 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3976 mono_arch_finish_init ();
3980 /* This must come after mono_init () in the aot-only case */
3981 mono_exceptions_init ();
3983 /* This should come after mono_init () too */
3987 mono_create_helper_signatures ();
3990 register_jit_stats ();
3992 #define JIT_CALLS_WORK
3993 #ifdef JIT_CALLS_WORK
3994 /* Needs to be called here since register_jit_icall depends on it */
3995 mono_marshal_init ();
3997 mono_arch_register_lowlevel_calls ();
4001 mono_generic_sharing_init ();
4004 #ifdef MONO_ARCH_SIMD_INTRINSICS
4005 mono_simd_intrinsics_init ();
4008 mono_tasklets_init ();
4010 register_trampolines (domain);
4012 if (mono_compile_aot)
4014 * Avoid running managed code when AOT compiling, since the platform
4015 * might only support aot-only execution.
4017 mono_runtime_set_no_exec (TRUE);
4019 mono_mem_account_register_counters ();
4021 #define JIT_RUNTIME_WORKS
4022 #ifdef JIT_RUNTIME_WORKS
4023 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4024 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4025 mono_error_assert_ok (&error);
4026 mono_thread_attach (domain);
4027 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4030 if (mono_profiler_sampling_enabled ())
4031 mono_runtime_setup_stat_profiler ();
4033 MONO_PROFILER_RAISE (runtime_initialized, ());
4035 MONO_VES_INIT_END ();
4041 register_icalls (void)
4043 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4044 ves_icall_get_frame_info);
4045 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4046 ves_icall_get_trace);
4047 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4048 mono_runtime_install_handlers);
4049 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4050 mono_runtime_cleanup_handlers);
4052 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4053 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4054 mono_debugger_agent_unhandled_exception);
4058 * It's important that we pass `TRUE` as the last argument here, as
4059 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4060 * *did* emit a wrapper, we'd be looking at infinite recursion since
4061 * the wrapper would call the icall which would call the wrapper and
4064 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4065 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4066 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4068 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4069 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4070 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4071 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4072 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4073 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4075 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4076 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4077 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4078 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4079 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4080 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4081 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4082 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4083 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4085 // FIXME: This is broken
4086 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4089 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4090 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4091 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4092 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4093 register_icall (mono_thread_self_abort, "mono_thread_self_abort", "void", FALSE);
4094 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4095 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4097 if (mono_threads_is_coop_enabled ())
4098 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4100 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4101 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4102 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4103 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4104 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4105 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4107 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4108 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4109 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4112 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4113 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4114 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4115 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4118 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4119 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4120 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4121 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4122 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4125 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4126 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4129 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4130 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4131 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4134 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4135 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4138 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4139 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4140 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4141 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4142 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4143 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4144 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4147 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4148 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4149 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4152 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4153 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);
4155 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4156 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4158 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4159 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4161 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4162 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);
4164 #ifdef MONO_ARCH_EMULATE_FREM
4165 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4166 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4169 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4170 if (mono_arch_is_soft_float ()) {
4171 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4172 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4173 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4174 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4175 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4176 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4177 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4178 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4179 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4180 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4181 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4182 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4184 #if SIZEOF_VOID_P == 4
4185 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4188 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4189 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4190 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4191 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4192 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4193 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4194 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4195 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4196 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4197 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4199 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4200 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4201 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4202 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4203 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4205 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4206 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4207 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4208 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4211 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4213 #ifdef COMPRESSED_INTERFACE_BITMAP
4214 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4217 #if SIZEOF_REGISTER == 4
4218 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4220 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4223 /* other jit icalls */
4224 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4225 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4226 "ptr ptr ptr", FALSE);
4227 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4228 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4229 "ptr ptr ptr ptr", FALSE);
4230 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4231 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4232 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4233 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4234 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4235 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4236 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4237 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4238 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4239 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4240 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4241 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4242 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4243 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4244 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4245 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4246 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4247 register_icall (mono_break, "mono_break", NULL, TRUE);
4248 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4249 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4250 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4251 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4252 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4253 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4254 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4255 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4256 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4257 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4258 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4260 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4261 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4263 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4264 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4265 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4266 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4267 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4269 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4271 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4272 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4273 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4274 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4276 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4277 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4278 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4279 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4280 /* This needs a wrapper so it can have a preserveall cconv */
4281 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4282 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4283 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4284 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4285 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4286 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4287 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4289 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4290 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4291 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4292 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4295 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4297 /* Register tls icalls */
4298 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4299 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4300 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4301 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4302 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4303 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4304 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4305 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4306 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4307 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4310 MonoJitStats mono_jit_stats = {0};
4313 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4314 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4316 MONO_NO_SANITIZE_THREAD
4318 print_jit_stats (void)
4320 if (mono_jit_stats.enabled) {
4321 g_print ("Mono Jit statistics\n");
4322 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4323 mono_jit_stats.max_ratio_method);
4324 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4325 mono_jit_stats.biggest_method);
4327 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4328 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4329 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4330 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4331 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4332 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4333 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4334 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4336 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4337 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4338 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4340 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4341 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4342 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4343 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4345 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4346 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4347 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4348 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4349 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4350 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4351 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4352 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4354 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4355 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4356 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4358 g_free (mono_jit_stats.max_ratio_method);
4359 mono_jit_stats.max_ratio_method = NULL;
4360 g_free (mono_jit_stats.biggest_method);
4361 mono_jit_stats.biggest_method = NULL;
4366 mini_cleanup (MonoDomain *domain)
4368 if (mono_profiler_sampling_enabled ())
4369 mono_runtime_shutdown_stat_profiler ();
4371 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4374 cominterop_release_all_rcws ();
4377 #ifndef MONO_CROSS_COMPILE
4379 * mono_domain_finalize () needs to be called early since it needs the
4380 * execution engine still fully working (it may invoke managed finalizers).
4382 mono_domain_finalize (domain, 2000);
4385 /* This accesses metadata so needs to be called before runtime shutdown */
4388 #ifndef MONO_CROSS_COMPILE
4389 mono_runtime_cleanup (domain);
4392 mono_threadpool_cleanup ();
4394 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4396 mono_profiler_cleanup ();
4398 if (profile_options)
4399 g_ptr_array_free (profile_options, TRUE);
4401 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4403 mono_icall_cleanup ();
4405 mono_runtime_cleanup_handlers ();
4407 #ifndef MONO_CROSS_COMPILE
4408 mono_domain_free (domain, TRUE);
4413 mono_llvm_cleanup ();
4416 mono_aot_cleanup ();
4418 mono_trampolines_cleanup ();
4420 mono_unwind_cleanup ();
4422 mono_code_manager_destroy (global_codeman);
4423 g_free (vtable_trampolines);
4425 mini_jit_cleanup ();
4427 mono_tramp_info_cleanup ();
4429 mono_arch_cleanup ();
4431 mono_generic_sharing_cleanup ();
4435 mono_trace_cleanup ();
4437 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4439 if (mono_inject_async_exc_method)
4440 mono_method_desc_free (mono_inject_async_exc_method);
4442 mono_tls_free_keys ();
4444 mono_os_mutex_destroy (&jit_mutex);
4446 mono_code_manager_cleanup ();
4449 mono_w32handle_cleanup ();
4454 mono_set_defaults (int verbose_level, guint32 opts)
4456 mini_verbose = verbose_level;
4457 mono_set_optimizations (opts);
4461 mono_disable_optimizations (guint32 opts)
4463 default_opt &= ~opts;
4467 mono_set_optimizations (guint32 opts)
4470 default_opt_set = TRUE;
4471 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4472 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4475 mono_set_generic_sharing_vt_supported (TRUE);
4480 mono_set_verbose_level (guint32 level)
4482 mini_verbose = level;
4486 * mono_get_runtime_build_info:
4487 * The returned string is owned by the caller. The returned string
4488 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4489 * \returns the runtime version + build date in string format.
4492 mono_get_runtime_build_info (void)
4494 if (mono_build_date)
4495 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4497 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4501 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4503 GHashTable *assemblies = (GHashTable*)user_data;
4504 MonoImage *image = mono_assembly_get_image (ass);
4505 MonoMethod *method, *invoke;
4508 if (g_hash_table_lookup (assemblies, ass))
4511 g_hash_table_insert (assemblies, ass, ass);
4513 if (mini_verbose > 0)
4514 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4516 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4519 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4521 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4524 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4526 if (method->is_generic || mono_class_is_gtd (method->klass))
4530 if (mini_verbose > 1) {
4531 char * desc = mono_method_full_name (method, TRUE);
4532 g_print ("Compiling %d %s\n", count, desc);
4535 mono_compile_method_checked (method, &error);
4536 if (!is_ok (&error)) {
4537 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4540 if (strcmp (method->name, "Finalize") == 0) {
4541 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4542 mono_compile_method_checked (invoke, &error);
4543 mono_error_assert_ok (&error);
4545 #ifndef DISABLE_REMOTING
4546 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4547 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4548 mono_compile_method_checked (invoke, &error);
4549 mono_error_assert_ok (&error);
4554 /* Load and precompile referenced assemblies as well */
4555 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4556 mono_assembly_load_reference (image, i);
4557 if (image->references [i])
4558 mono_precompile_assembly (image->references [i], assemblies);
4562 void mono_precompile_assemblies ()
4564 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4566 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4568 g_hash_table_destroy (assemblies);
4573 * Have to export this for AOT.
4576 mono_personality (void)
4579 g_assert_not_reached ();
4583 static MonoBreakPolicy
4584 always_insert_breakpoint (MonoMethod *method)
4586 return MONO_BREAK_POLICY_ALWAYS;
4589 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4592 * mono_set_break_policy:
4593 * \param policy_callback the new callback function
4595 * Allow embedders to decide whether to actually obey breakpoint instructions
4596 * (both break IL instructions and \c Debugger.Break method calls), for example
4597 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4598 * untrusted or semi-trusted code.
4600 * \p policy_callback will be called every time a break point instruction needs to
4601 * be inserted with the method argument being the method that calls \c Debugger.Break
4602 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4603 * if it wants the breakpoint to not be effective in the given method.
4604 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4607 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4609 if (policy_callback)
4610 break_policy_func = policy_callback;
4612 break_policy_func = always_insert_breakpoint;
4616 mini_should_insert_breakpoint (MonoMethod *method)
4618 switch (break_policy_func (method)) {
4619 case MONO_BREAK_POLICY_ALWAYS:
4621 case MONO_BREAK_POLICY_NEVER:
4623 case MONO_BREAK_POLICY_ON_DBG:
4624 g_warning ("mdb no longer supported");
4627 g_warning ("Incorrect value returned from break policy callback");
4632 // Custom handlers currently only implemented by Windows.
4635 mono_runtime_install_custom_handlers (const char *handlers)
4641 mono_runtime_install_custom_handlers_usage (void)
4644 "Custom Handlers:\n"
4645 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4646 " separated list of available handlers to install.\n"
4648 "No handlers supported on current platform.\n");
4650 #endif /* HOST_WIN32 */