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 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 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);
2626 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2627 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2631 domain_info = domain_jit_info (domain);
2633 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2636 if (mono_security_core_clr_enabled ()) {
2638 * This might be redundant since mono_class_vtable () already does this,
2639 * but keep it just in case for moonlight.
2641 mono_class_setup_vtable (method->klass);
2642 if (mono_class_has_failure (method->klass)) {
2643 mono_error_set_for_class_failure (error, method->klass);
2645 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2650 gpointer compiled_method;
2653 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2654 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2656 * Array Get/Set/Address methods. The JIT implements them using inline code
2657 * inside the runtime invoke wrappers, so no need to compile them.
2659 if (mono_aot_only) {
2661 * Call a wrapper, since the runtime invoke wrapper was not generated.
2663 MonoMethod *wrapper;
2665 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2666 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2674 compiled_method = mono_jit_compile_method (callee, error);
2675 if (!compiled_method) {
2676 g_assert (!mono_error_ok (error));
2680 if (mono_llvm_only) {
2681 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2682 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2683 if (callee_gsharedvt)
2684 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2687 if (!callee_gsharedvt)
2688 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2690 compiled_method = NULL;
2693 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2694 if (!mono_error_ok (error))
2697 mono_domain_lock (domain);
2698 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2699 mono_domain_unlock (domain);
2707 * We need this here because mono_marshal_get_runtime_invoke can place
2708 * the helper method in System.Object and not the target class.
2710 if (!mono_runtime_class_init_full (info->vtable, error)) {
2712 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2716 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2717 we always catch the exception and propagate it through the MonoError */
2718 gboolean catchExcInMonoError =
2719 (exc == NULL) && mono_threads_is_coop_enabled ();
2720 MonoObject *invoke_exc = NULL;
2721 if (catchExcInMonoError)
2724 /* The wrappers expect this to be initialized to NULL */
2728 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2729 if (info->dyn_call_info) {
2730 MonoMethodSignature *sig = mono_method_signature (method);
2732 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2735 guint8 retval [256];
2737 if (!dyn_runtime_invoke) {
2738 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2739 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2740 if (!mono_error_ok (error))
2744 /* Convert the arguments to the format expected by start_dyn_call () */
2745 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2748 args [pindex ++] = &obj;
2749 for (i = 0; i < sig->param_count; ++i) {
2750 MonoType *t = sig->params [i];
2753 args [pindex ++] = ¶ms [i];
2754 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2755 args [pindex ++] = ¶ms [i];
2757 args [pindex ++] = params [i];
2761 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2763 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2765 dyn_runtime_invoke (buf, exc, info->compiled_method);
2766 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2768 if (catchExcInMonoError && *exc != NULL) {
2769 mono_error_set_exception_instance (error, (MonoException*) *exc);
2773 if (info->ret_box_class)
2774 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2776 return *(MonoObject**)retval;
2782 if (mono_llvm_only) {
2783 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2787 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2789 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2791 if (catchExcInMonoError && *exc != NULL)
2792 mono_error_set_exception_instance (error, (MonoException*) *exc);
2801 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2804 * mini_llvmonly_initial_imt_tramp:
2806 * This function is called the first time a call is made through an IMT trampoline.
2807 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2810 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2812 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2817 mono_vtable_build_imt_slot (info->vtable, info->slot);
2819 imt = (gpointer*)info->vtable;
2820 imt -= MONO_IMT_SIZE;
2822 /* Return what the real IMT trampoline returns */
2823 ftndesc = imt [info->slot];
2826 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2827 /* Happens when the imt slot contains only a generic virtual method */
2829 return func ((gpointer *)ftndesc [1], imt_method);
2832 /* This is called indirectly through an imt slot. */
2834 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2838 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2839 while (arg [i] && arg [i] != imt_method)
2846 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2848 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2850 //g_assert (arg [0] == imt_method);
2855 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2857 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2858 if (arg [0] == imt_method)
2865 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2867 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2868 if (arg [0] == imt_method)
2870 else if (arg [2] == imt_method)
2877 * A version of the imt trampoline used for generic virtual/variant iface methods.
2878 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2879 * in the search table. The original JIT code had a 'fallback' trampoline it could
2880 * call, but we can't do that, so we just return NULL, and the compiled code
2884 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2888 while (arg [i] && arg [i] != imt_method)
2897 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2901 int i, index, real_count;
2902 gboolean virtual_generic = FALSE;
2905 * Create an array which is passed to the imt trampoline functions.
2906 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2910 for (i = 0; i < count; ++i) {
2911 MonoIMTCheckItem *item = imt_entries [i];
2913 if (item->is_equals)
2915 if (item->has_target_code)
2916 virtual_generic = TRUE;
2920 * Initialize all vtable entries reachable from this imt slot, so the compiled
2921 * code doesn't have to check it.
2923 for (i = 0; i < count; ++i) {
2924 MonoIMTCheckItem *item = imt_entries [i];
2927 if (!item->is_equals || item->has_target_code)
2929 vt_slot = item->value.vtable_slot;
2930 mono_init_vtable_slot (vtable, vt_slot);
2933 /* Save the entries into an array */
2934 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2936 for (i = 0; i < count; ++i) {
2937 MonoIMTCheckItem *item = imt_entries [i];
2939 if (!item->is_equals)
2942 g_assert (item->key);
2943 buf [(index * 2)] = item->key;
2944 if (item->has_target_code)
2945 buf [(index * 2) + 1] = item->value.target_code;
2947 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2950 buf [(index * 2)] = NULL;
2951 buf [(index * 2) + 1] = fail_tramp;
2954 * Return a function descriptor for a C function with 'buf' as its argument.
2955 * It will by called by JITted code.
2957 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2958 switch (real_count) {
2960 res [0] = mono_llvmonly_imt_tramp_1;
2963 res [0] = mono_llvmonly_imt_tramp_2;
2966 res [0] = mono_llvmonly_imt_tramp_3;
2969 res [0] = mono_llvmonly_imt_tramp;
2972 if (virtual_generic || fail_tramp)
2973 res [0] = mono_llvmonly_fallback_imt_tramp;
2979 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2981 MonoException *exc = NULL;
2983 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2984 MONO_SIG_HANDLER_GET_CONTEXT;
2986 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2988 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2990 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2991 if (mono_arch_is_int_overflow (ctx, info))
2993 * The spec says this throws ArithmeticException, but MS throws the derived
2994 * OverflowException.
2996 exc = mono_get_exception_overflow ();
2998 exc = mono_get_exception_divide_by_zero ();
3000 exc = mono_get_exception_divide_by_zero ();
3004 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3007 mono_handle_native_crash ("SIGFPE", ctx, info);
3008 if (mono_do_crash_chaining) {
3009 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3014 mono_arch_handle_exception (ctx, exc);
3017 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3020 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3022 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3023 MONO_SIG_HANDLER_GET_CONTEXT;
3025 if (mono_runtime_get_no_exec ())
3029 mono_handle_native_crash ("SIGILL", ctx, info);
3030 if (mono_do_crash_chaining) {
3031 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3035 g_assert_not_reached ();
3038 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3039 #define HAVE_SIG_INFO
3042 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3045 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3046 gpointer fault_addr = NULL;
3047 #ifdef HAVE_SIG_INFO
3048 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3052 MONO_SIG_HANDLER_GET_CONTEXT;
3054 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3055 if (mono_arch_is_single_step_event (info, ctx)) {
3056 mono_debugger_agent_single_step_event (ctx);
3058 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3059 mono_debugger_agent_breakpoint_hit (ctx);
3064 #if defined(HAVE_SIG_INFO)
3065 #if !defined(HOST_WIN32)
3066 fault_addr = info->si_addr;
3067 if (mono_aot_is_pagefault (info->si_addr)) {
3068 mono_aot_handle_pagefault (info->si_addr);
3073 /* The thread might no be registered with the runtime */
3074 if (!mono_domain_get () || !jit_tls) {
3075 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3077 mono_handle_native_crash ("SIGSEGV", ctx, info);
3078 if (mono_do_crash_chaining) {
3079 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3085 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3087 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3088 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3091 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3092 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3093 fault_addr = info->si_addr;
3094 if (fault_addr == NULL) {
3097 mono_sigctx_to_monoctx (ctx, &mctx);
3099 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3103 if (jit_tls->stack_size &&
3104 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3106 * The hard-guard page has been hit: there is not much we can do anymore
3107 * Print a hopefully clear message and abort.
3109 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3110 g_assert_not_reached ();
3112 /* The original handler might not like that it is executed on an altstack... */
3113 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3116 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3121 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3124 mono_handle_native_crash ("SIGSEGV", ctx, info);
3126 if (mono_do_crash_chaining) {
3127 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3132 mono_arch_handle_exception (ctx, NULL);
3136 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3139 MONO_SIG_HANDLER_GET_CONTEXT;
3141 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3143 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3145 mono_arch_handle_exception (ctx, exc);
3147 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3150 #ifndef DISABLE_REMOTING
3151 /* mono_jit_create_remoting_trampoline:
3152 * @method: pointer to the method info
3154 * Creates a trampoline which calls the remoting functions. This
3155 * is used in the vtable of transparent proxies.
3157 * Returns: a pointer to the newly created code
3160 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3163 guint8 *addr = NULL;
3167 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3168 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3172 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3173 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3174 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3177 addr = (guint8 *)mono_compile_method_checked (nm, error);
3178 return_val_if_nok (error, NULL);
3179 return mono_get_addr_from_ftnptr (addr);
3183 static G_GNUC_UNUSED void
3184 no_imt_trampoline (void)
3186 g_assert_not_reached ();
3189 static G_GNUC_UNUSED void
3190 no_vcall_trampoline (void)
3192 g_assert_not_reached ();
3195 static gpointer *vtable_trampolines;
3196 static int vtable_trampolines_size;
3199 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3201 int index = slot_index + MONO_IMT_SIZE;
3203 if (mono_llvm_only) {
3204 if (slot_index < 0) {
3205 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3206 // FIXME: Memory management
3207 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3208 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3211 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3213 mono_memory_barrier ();
3220 g_assert (slot_index >= - MONO_IMT_SIZE);
3221 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3223 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3227 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3228 while (new_size <= index)
3230 new_table = g_new0 (gpointer, new_size);
3232 if (vtable_trampolines)
3233 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3234 g_free (vtable_trampolines);
3235 mono_memory_barrier ();
3236 vtable_trampolines = (void **)new_table;
3237 vtable_trampolines_size = new_size;
3242 if (!vtable_trampolines [index])
3243 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3244 return vtable_trampolines [index];
3248 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3250 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3254 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3259 gpointer *imt = (gpointer*)vt;
3260 imt -= MONO_IMT_SIZE;
3262 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3266 is_callee_gsharedvt_variable (gpointer addr)
3269 gboolean callee_gsharedvt;
3271 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3273 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3274 if (callee_gsharedvt)
3275 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3276 return callee_gsharedvt;
3280 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3282 gpointer arg = NULL;
3284 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3285 arg = mini_method_get_rgctx (method);
3288 * Avoid adding gsharedvt in wrappers since they might not exist if
3289 * this delegate is called through a gsharedvt delegate invoke wrapper.
3290 * Instead, encode that the method is gsharedvt in del->extra_arg,
3291 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3293 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3294 g_assert ((((mgreg_t)arg) & 1) == 0);
3295 arg = (gpointer)(((mgreg_t)arg) | 1);
3301 mini_init_delegate (MonoDelegate *del)
3304 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3305 #ifdef ENABLE_INTERPRETER
3306 if (mono_use_interpreter)
3307 mono_interp_init_delegate (del);
3312 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3316 abs_offset = offset;
3318 abs_offset = - abs_offset;
3319 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3323 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3325 gboolean is_virtual_generic, is_interface, load_imt_reg;
3328 static guint8 **cache = NULL;
3329 static int cache_size = 0;
3334 if (MONO_TYPE_ISSTRUCT (sig->ret))
3337 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3338 is_interface = mono_class_is_interface (method->klass);
3339 load_imt_reg = is_virtual_generic || is_interface;
3342 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3344 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3346 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3347 g_assert (idx >= 0);
3349 /* Resize the cache to idx + 1 */
3350 if (cache_size < idx + 1) {
3352 if (cache_size < idx + 1) {
3354 int new_cache_size = idx + 1;
3356 new_cache = g_new0 (guint8*, new_cache_size);
3358 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3361 mono_memory_barrier ();
3363 cache_size = new_cache_size;
3371 /* FIXME Support more cases */
3372 if (mono_aot_only) {
3373 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3374 g_assert (cache [idx]);
3376 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3382 * mini_parse_debug_option:
3383 * @option: The option to parse.
3385 * Parses debug options for the mono runtime. The options are the same as for
3386 * the MONO_DEBUG environment variable.
3390 mini_parse_debug_option (const char *option)
3392 if (!strcmp (option, "handle-sigint"))
3393 debug_options.handle_sigint = TRUE;
3394 else if (!strcmp (option, "keep-delegates"))
3395 debug_options.keep_delegates = TRUE;
3396 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3397 debug_options.reverse_pinvoke_exceptions = TRUE;
3398 else if (!strcmp (option, "collect-pagefault-stats"))
3399 debug_options.collect_pagefault_stats = TRUE;
3400 else if (!strcmp (option, "break-on-unverified"))
3401 debug_options.break_on_unverified = TRUE;
3402 else if (!strcmp (option, "no-gdb-backtrace"))
3403 debug_options.no_gdb_backtrace = TRUE;
3404 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3405 debug_options.suspend_on_native_crash = TRUE;
3406 else if (!strcmp (option, "suspend-on-exception"))
3407 debug_options.suspend_on_exception = TRUE;
3408 else if (!strcmp (option, "suspend-on-unhandled"))
3409 debug_options.suspend_on_unhandled = TRUE;
3410 else if (!strcmp (option, "dont-free-domains"))
3411 mono_dont_free_domains = TRUE;
3412 else if (!strcmp (option, "dyn-runtime-invoke"))
3413 debug_options.dyn_runtime_invoke = TRUE;
3414 else if (!strcmp (option, "gdb"))
3415 debug_options.gdb = TRUE;
3416 else if (!strcmp (option, "lldb"))
3417 debug_options.lldb = TRUE;
3418 else if (!strcmp (option, "explicit-null-checks"))
3419 debug_options.explicit_null_checks = TRUE;
3420 else if (!strcmp (option, "gen-seq-points"))
3421 debug_options.gen_sdb_seq_points = TRUE;
3422 else if (!strcmp (option, "gen-compact-seq-points"))
3423 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3424 else if (!strcmp (option, "no-compact-seq-points"))
3425 debug_options.no_seq_points_compact_data = TRUE;
3426 else if (!strcmp (option, "single-imm-size"))
3427 debug_options.single_imm_size = TRUE;
3428 else if (!strcmp (option, "init-stacks"))
3429 debug_options.init_stacks = TRUE;
3430 else if (!strcmp (option, "casts"))
3431 debug_options.better_cast_details = TRUE;
3432 else if (!strcmp (option, "soft-breakpoints"))
3433 debug_options.soft_breakpoints = TRUE;
3434 else if (!strcmp (option, "check-pinvoke-callconv"))
3435 debug_options.check_pinvoke_callconv = TRUE;
3436 else if (!strcmp (option, "use-fallback-tls"))
3437 debug_options.use_fallback_tls = TRUE;
3438 else if (!strcmp (option, "debug-domain-unload"))
3439 mono_enable_debug_domain_unload (TRUE);
3440 else if (!strcmp (option, "partial-sharing"))
3441 mono_set_partial_sharing_supported (TRUE);
3442 else if (!strcmp (option, "align-small-structs"))
3443 mono_align_small_structs = TRUE;
3444 else if (!strcmp (option, "native-debugger-break"))
3445 debug_options.native_debugger_break = TRUE;
3446 else if (!strcmp (option, "disable_omit_fp"))
3447 debug_options.disable_omit_fp = TRUE;
3455 mini_parse_debug_options (void)
3457 char *options = g_getenv ("MONO_DEBUG");
3458 gchar **args, **ptr;
3463 args = g_strsplit (options, ",", -1);
3466 for (ptr = args; ptr && *ptr; ptr++) {
3467 const char *arg = *ptr;
3469 if (!mini_parse_debug_option (arg)) {
3470 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3471 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");
3480 mini_get_debug_options (void)
3482 return &debug_options;
3486 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3488 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3491 gpointer* desc = NULL;
3493 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3495 # if defined(__ppc64__) || defined(__powerpc64__)
3497 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3503 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3509 mini_get_addr_from_ftnptr (gpointer descr)
3511 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3512 return *(gpointer*)descr;
3519 register_jit_stats (void)
3521 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3522 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3523 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3524 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3525 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3526 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3527 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);
3528 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3529 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3530 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3531 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3532 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3533 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3534 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3535 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3536 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3537 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3538 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3539 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3540 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3541 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3542 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3543 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3544 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3545 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3546 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3547 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3548 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3549 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3550 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3551 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3552 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3553 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3554 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3555 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3556 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3557 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3558 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3559 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3560 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3561 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3562 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3563 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3564 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3565 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3566 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3567 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3568 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3569 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3570 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3571 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3572 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3573 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3574 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3575 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3576 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3577 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3578 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3579 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3580 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3581 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3584 static void runtime_invoke_info_free (gpointer value);
3587 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3589 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3590 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3592 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3596 class_method_pair_hash (gconstpointer data)
3598 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3600 return (gsize)pair->klass ^ (gsize)pair->method;
3604 mini_create_jit_domain_info (MonoDomain *domain)
3606 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3608 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3609 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3610 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3611 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3612 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3613 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3614 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3615 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3616 mono_jit_code_hash_init (&info->interp_code_hash);
3618 domain->runtime_info = info;
3622 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3624 MonoJumpList *jlist = (MonoJumpList *)value;
3625 g_slist_free (jlist->list);
3629 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3631 GSList *list = (GSList *)value;
3632 g_slist_free (list);
3636 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3638 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3639 mono_code_manager_destroy (di->code_mp);
3644 runtime_invoke_info_free (gpointer value)
3646 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3648 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3649 if (info->dyn_call_info)
3650 mono_arch_dyn_call_free (info->dyn_call_info);
3656 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3658 g_slist_free (value);
3662 mini_free_jit_domain_info (MonoDomain *domain)
3664 MonoJitDomainInfo *info = domain_jit_info (domain);
3666 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3667 g_hash_table_destroy (info->jump_target_hash);
3668 if (info->jump_target_got_slot_hash) {
3669 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3670 g_hash_table_destroy (info->jump_target_got_slot_hash);
3672 if (info->dynamic_code_hash) {
3673 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3674 g_hash_table_destroy (info->dynamic_code_hash);
3676 if (info->method_code_hash)
3677 g_hash_table_destroy (info->method_code_hash);
3678 g_hash_table_destroy (info->jump_trampoline_hash);
3679 g_hash_table_destroy (info->jit_trampoline_hash);
3680 g_hash_table_destroy (info->delegate_trampoline_hash);
3681 if (info->static_rgctx_trampoline_hash)
3682 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3683 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3684 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3685 g_hash_table_destroy (info->seq_points);
3686 g_hash_table_destroy (info->arch_seq_points);
3687 if (info->agent_info)
3688 mono_debugger_agent_free_domain_info (domain);
3689 if (info->gsharedvt_arg_tramp_hash)
3690 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3691 if (info->llvm_jit_callees) {
3692 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3693 g_hash_table_destroy (info->llvm_jit_callees);
3695 mono_internal_hash_table_destroy (&info->interp_code_hash);
3697 mono_llvm_free_domain_info (domain);
3700 g_free (domain->runtime_info);
3701 domain->runtime_info = NULL;
3704 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3707 code_manager_chunk_new (void *chunk, int size)
3709 mono_arch_code_chunk_new (chunk, size);
3713 code_manager_chunk_destroy (void *chunk)
3715 mono_arch_code_chunk_destroy (chunk);
3722 llvm_init_inner (void)
3724 if (!mono_llvm_load (NULL))
3735 * Load and initialize LLVM support.
3736 * Return TRUE on success.
3739 mini_llvm_init (void)
3742 static gboolean llvm_inited;
3743 static gboolean init_result;
3745 mono_loader_lock_if_inited ();
3747 init_result = llvm_init_inner ();
3750 mono_loader_unlock_if_inited ();
3758 mini_add_profiler_argument (const char *desc)
3760 if (!profile_options)
3761 profile_options = g_ptr_array_new ();
3763 g_ptr_array_add (profile_options, (gpointer) desc);
3767 mini_init (const char *filename, const char *runtime_version)
3771 MonoRuntimeCallbacks callbacks;
3772 MonoThreadInfoRuntimeCallbacks ticallbacks;
3773 MonoCodeManagerCallbacks code_manager_callbacks;
3775 MONO_VES_INIT_BEGIN ();
3777 CHECKED_MONO_INIT ();
3779 #if defined(__linux__)
3780 if (access ("/proc/self/maps", F_OK) != 0) {
3781 g_print ("Mono requires /proc to be mounted.\n");
3786 #ifdef ENABLE_INTERPRETER
3787 mono_interp_init ();
3790 mono_os_mutex_init_recursive (&jit_mutex);
3792 mono_cross_helpers_run ();
3794 mono_counters_init ();
3798 mini_jit_init_job_control ();
3800 /* Happens when using the embedding interface */
3801 if (!default_opt_set)
3802 default_opt = mono_parse_default_optimizations (NULL);
3804 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3806 mono_set_generic_sharing_vt_supported (TRUE);
3809 mono_set_generic_sharing_vt_supported (TRUE);
3812 mono_tls_init_runtime_keys ();
3814 if (!global_codeman)
3815 global_codeman = mono_code_manager_new ();
3817 memset (&callbacks, 0, sizeof (callbacks));
3818 callbacks.create_ftnptr = mini_create_ftnptr;
3819 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3820 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3821 callbacks.set_cast_details = mono_set_cast_details;
3822 callbacks.debug_log = mono_debugger_agent_debug_log;
3823 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3824 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3825 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3826 callbacks.imt_entry_inited = mini_imt_entry_inited;
3827 callbacks.init_delegate = mini_init_delegate;
3828 #define JIT_INVOKE_WORKS
3829 #ifdef JIT_INVOKE_WORKS
3830 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3832 #define JIT_TRAMPOLINES_WORK
3833 #ifdef JIT_TRAMPOLINES_WORK
3834 callbacks.compile_method = mono_jit_compile_method;
3835 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3836 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3837 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3838 callbacks.free_method = mono_jit_free_method;
3839 #ifndef DISABLE_REMOTING
3840 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3844 mono_install_callbacks (&callbacks);
3846 memset (&ticallbacks, 0, sizeof (ticallbacks));
3847 ticallbacks.setup_async_callback = mono_setup_async_callback;
3848 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3849 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3850 ticallbacks.thread_state_init = mono_thread_state_init;
3853 mono_w32handle_init ();
3856 mono_thread_info_runtime_init (&ticallbacks);
3858 if (g_hasenv ("MONO_DEBUG")) {
3859 mini_parse_debug_options ();
3862 mono_code_manager_init ();
3864 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3865 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3866 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3867 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3869 mono_code_manager_install_callbacks (&code_manager_callbacks);
3873 mono_arch_cpu_init ();
3877 mono_unwind_init ();
3879 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3880 mono_lldb_init ("");
3881 mono_dont_free_domains = TRUE;
3884 #ifdef XDEBUG_ENABLED
3885 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3887 mono_xdebug_init (mono_xdebug);
3888 g_free (mono_xdebug);
3889 /* So methods for multiple domains don't have the same address */
3890 mono_dont_free_domains = TRUE;
3891 mono_using_xdebug = TRUE;
3892 } else if (mini_get_debug_options ()->gdb) {
3893 mono_xdebug_init ((char*)"gdb");
3894 mono_dont_free_domains = TRUE;
3895 mono_using_xdebug = TRUE;
3900 if (mono_use_llvm) {
3901 if (!mono_llvm_load (NULL)) {
3902 mono_use_llvm = FALSE;
3903 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3910 mono_trampolines_init ();
3912 if (default_opt & MONO_OPT_AOT)
3915 mono_debugger_agent_init ();
3917 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3918 mono_set_generic_sharing_supported (TRUE);
3921 mono_thread_info_signals_init ();
3923 #ifndef MONO_CROSS_COMPILE
3924 mono_runtime_install_handlers ();
3926 mono_threads_install_cleanup (mini_thread_cleanup);
3928 #ifdef JIT_TRAMPOLINES_WORK
3929 mono_install_create_domain_hook (mini_create_jit_domain_info);
3930 mono_install_free_domain_hook (mini_free_jit_domain_info);
3932 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3933 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3934 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3936 mono_profiler_state.context_enable = mini_profiler_context_enable;
3937 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
3938 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
3939 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
3940 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
3941 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
3943 if (profile_options)
3944 for (guint i = 0; i < profile_options->len; i++)
3945 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
3947 mono_profiler_started ();
3949 if (debug_options.collect_pagefault_stats)
3950 mono_aot_set_make_unreadable (TRUE);
3952 if (runtime_version)
3953 domain = mono_init_version (filename, runtime_version);
3955 domain = mono_init_from_assembly (filename, filename);
3957 if (mono_aot_only) {
3958 /* This helps catch code allocation requests */
3959 mono_code_manager_set_read_only (domain->code_mp);
3960 mono_marshal_use_aot_wrappers (TRUE);
3963 if (mono_llvm_only) {
3964 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3965 mono_set_always_build_imt_trampolines (TRUE);
3966 } else if (mono_aot_only) {
3967 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3969 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3972 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3973 mono_arch_finish_init ();
3977 /* This must come after mono_init () in the aot-only case */
3978 mono_exceptions_init ();
3980 /* This should come after mono_init () too */
3984 mono_create_helper_signatures ();
3987 register_jit_stats ();
3989 #define JIT_CALLS_WORK
3990 #ifdef JIT_CALLS_WORK
3991 /* Needs to be called here since register_jit_icall depends on it */
3992 mono_marshal_init ();
3994 mono_arch_register_lowlevel_calls ();
3998 mono_generic_sharing_init ();
4001 #ifdef MONO_ARCH_SIMD_INTRINSICS
4002 mono_simd_intrinsics_init ();
4005 mono_tasklets_init ();
4007 register_trampolines (domain);
4009 if (mono_compile_aot)
4011 * Avoid running managed code when AOT compiling, since the platform
4012 * might only support aot-only execution.
4014 mono_runtime_set_no_exec (TRUE);
4016 mono_mem_account_register_counters ();
4018 #define JIT_RUNTIME_WORKS
4019 #ifdef JIT_RUNTIME_WORKS
4020 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4021 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4022 mono_error_assert_ok (&error);
4023 mono_thread_attach (domain);
4024 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4027 if (mono_profiler_sampling_enabled ())
4028 mono_runtime_setup_stat_profiler ();
4030 MONO_PROFILER_RAISE (runtime_initialized, ());
4032 MONO_VES_INIT_END ();
4038 register_icalls (void)
4040 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4041 ves_icall_get_frame_info);
4042 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4043 ves_icall_get_trace);
4044 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4045 mono_runtime_install_handlers);
4046 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4047 mono_runtime_cleanup_handlers);
4049 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4050 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4051 mono_debugger_agent_unhandled_exception);
4055 * It's important that we pass `TRUE` as the last argument here, as
4056 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4057 * *did* emit a wrapper, we'd be looking at infinite recursion since
4058 * the wrapper would call the icall which would call the wrapper and
4061 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4062 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4063 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4065 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4066 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4067 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4068 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4069 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4070 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4072 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4073 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4074 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4075 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4076 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4077 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4078 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4079 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4080 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4082 // FIXME: This is broken
4083 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4086 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4087 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4088 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4089 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4090 register_icall (mono_thread_self_abort, "mono_thread_self_abort", "void", FALSE);
4091 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4092 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4094 if (mono_threads_is_coop_enabled ())
4095 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4097 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4098 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4099 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4100 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4101 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4102 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4104 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4105 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4106 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4109 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4110 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4111 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4112 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4115 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4116 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4117 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4118 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4119 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4122 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4123 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4126 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4127 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4128 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4131 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4132 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4135 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4136 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4137 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4138 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4139 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4140 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4141 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4144 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4145 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4146 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4149 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4150 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);
4152 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4153 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4155 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4156 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4158 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4159 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);
4161 #ifdef MONO_ARCH_EMULATE_FREM
4162 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4163 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4166 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4167 if (mono_arch_is_soft_float ()) {
4168 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4169 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4170 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4171 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4172 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4173 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4174 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4175 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4176 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4177 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4178 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4179 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4181 #if SIZEOF_VOID_P == 4
4182 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4185 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4186 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4187 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4188 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4189 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4190 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4191 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4192 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4193 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4194 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4196 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4197 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4198 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4199 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4200 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4202 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4203 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4204 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4205 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4208 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4210 #ifdef COMPRESSED_INTERFACE_BITMAP
4211 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4214 #if SIZEOF_REGISTER == 4
4215 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4217 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4220 /* other jit icalls */
4221 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4222 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4223 "ptr ptr ptr", FALSE);
4224 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4225 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4226 "ptr ptr ptr ptr", FALSE);
4227 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4228 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4229 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4230 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4231 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4232 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4233 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4234 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4235 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4236 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4237 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4238 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4239 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4240 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4241 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4242 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4243 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4244 register_icall (mono_break, "mono_break", NULL, TRUE);
4245 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4246 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4247 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4248 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4249 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4250 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4251 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4252 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4253 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4254 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4255 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4257 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4258 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4260 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4261 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4262 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4263 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4264 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4266 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4268 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4269 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4270 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4271 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4273 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4274 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4275 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4276 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4277 /* This needs a wrapper so it can have a preserveall cconv */
4278 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4279 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4280 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4281 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4282 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4283 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4284 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4286 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4287 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4288 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4289 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4292 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4294 /* Register tls icalls */
4295 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4296 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4297 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4298 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4299 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4300 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4301 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4302 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4303 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4304 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4307 MonoJitStats mono_jit_stats = {0};
4310 * Counters of mono_stats can be read without locking here.
4311 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4313 MONO_NO_SANITIZE_THREAD
4315 print_jit_stats (void)
4317 if (mono_jit_stats.enabled) {
4318 g_print ("Mono Jit statistics\n");
4319 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4320 mono_jit_stats.max_ratio_method);
4321 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4322 mono_jit_stats.biggest_method);
4324 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4325 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4326 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4327 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4328 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4329 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4330 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4331 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4333 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4334 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4335 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4337 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4338 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4339 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4340 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4342 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4343 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4344 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4345 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4346 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4347 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4348 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4349 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4351 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4352 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4353 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4355 g_free (mono_jit_stats.max_ratio_method);
4356 mono_jit_stats.max_ratio_method = NULL;
4357 g_free (mono_jit_stats.biggest_method);
4358 mono_jit_stats.biggest_method = NULL;
4363 mini_cleanup (MonoDomain *domain)
4365 if (mono_profiler_sampling_enabled ())
4366 mono_runtime_shutdown_stat_profiler ();
4368 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4371 cominterop_release_all_rcws ();
4374 #ifndef MONO_CROSS_COMPILE
4376 * mono_domain_finalize () needs to be called early since it needs the
4377 * execution engine still fully working (it may invoke managed finalizers).
4379 mono_domain_finalize (domain, 2000);
4382 /* This accesses metadata so needs to be called before runtime shutdown */
4385 #ifndef MONO_CROSS_COMPILE
4386 mono_runtime_cleanup (domain);
4389 mono_threadpool_cleanup ();
4391 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4393 mono_profiler_cleanup ();
4395 if (profile_options)
4396 g_ptr_array_free (profile_options, TRUE);
4398 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4400 mono_icall_cleanup ();
4402 mono_runtime_cleanup_handlers ();
4404 #ifndef MONO_CROSS_COMPILE
4405 mono_domain_free (domain, TRUE);
4410 mono_llvm_cleanup ();
4413 mono_aot_cleanup ();
4415 mono_trampolines_cleanup ();
4417 mono_unwind_cleanup ();
4419 mono_code_manager_destroy (global_codeman);
4420 g_free (vtable_trampolines);
4422 mini_jit_cleanup ();
4424 mono_tramp_info_cleanup ();
4426 mono_arch_cleanup ();
4428 mono_generic_sharing_cleanup ();
4432 mono_trace_cleanup ();
4434 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4436 if (mono_inject_async_exc_method)
4437 mono_method_desc_free (mono_inject_async_exc_method);
4439 mono_tls_free_keys ();
4441 mono_os_mutex_destroy (&jit_mutex);
4443 mono_code_manager_cleanup ();
4446 mono_w32handle_cleanup ();
4451 mono_set_defaults (int verbose_level, guint32 opts)
4453 mini_verbose = verbose_level;
4454 mono_set_optimizations (opts);
4458 mono_disable_optimizations (guint32 opts)
4460 default_opt &= ~opts;
4464 mono_set_optimizations (guint32 opts)
4467 default_opt_set = TRUE;
4468 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4469 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4472 mono_set_generic_sharing_vt_supported (TRUE);
4477 mono_set_verbose_level (guint32 level)
4479 mini_verbose = level;
4483 * mono_get_runtime_build_info:
4484 * The returned string is owned by the caller. The returned string
4485 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4486 * \returns the runtime version + build date in string format.
4489 mono_get_runtime_build_info (void)
4491 if (mono_build_date)
4492 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4494 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4498 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4500 GHashTable *assemblies = (GHashTable*)user_data;
4501 MonoImage *image = mono_assembly_get_image (ass);
4502 MonoMethod *method, *invoke;
4505 if (g_hash_table_lookup (assemblies, ass))
4508 g_hash_table_insert (assemblies, ass, ass);
4510 if (mini_verbose > 0)
4511 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4513 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4516 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4518 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4521 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4523 if (method->is_generic || mono_class_is_gtd (method->klass))
4527 if (mini_verbose > 1) {
4528 char * desc = mono_method_full_name (method, TRUE);
4529 g_print ("Compiling %d %s\n", count, desc);
4532 mono_compile_method_checked (method, &error);
4533 if (!is_ok (&error)) {
4534 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4537 if (strcmp (method->name, "Finalize") == 0) {
4538 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4539 mono_compile_method_checked (invoke, &error);
4540 mono_error_assert_ok (&error);
4542 #ifndef DISABLE_REMOTING
4543 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4544 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4545 mono_compile_method_checked (invoke, &error);
4546 mono_error_assert_ok (&error);
4551 /* Load and precompile referenced assemblies as well */
4552 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4553 mono_assembly_load_reference (image, i);
4554 if (image->references [i])
4555 mono_precompile_assembly (image->references [i], assemblies);
4559 void mono_precompile_assemblies ()
4561 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4563 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4565 g_hash_table_destroy (assemblies);
4570 * Have to export this for AOT.
4573 mono_personality (void)
4576 g_assert_not_reached ();
4580 static MonoBreakPolicy
4581 always_insert_breakpoint (MonoMethod *method)
4583 return MONO_BREAK_POLICY_ALWAYS;
4586 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4589 * mono_set_break_policy:
4590 * \param policy_callback the new callback function
4592 * Allow embedders to decide whether to actually obey breakpoint instructions
4593 * (both break IL instructions and \c Debugger.Break method calls), for example
4594 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4595 * untrusted or semi-trusted code.
4597 * \p policy_callback will be called every time a break point instruction needs to
4598 * be inserted with the method argument being the method that calls \c Debugger.Break
4599 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4600 * if it wants the breakpoint to not be effective in the given method.
4601 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4604 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4606 if (policy_callback)
4607 break_policy_func = policy_callback;
4609 break_policy_func = always_insert_breakpoint;
4613 mini_should_insert_breakpoint (MonoMethod *method)
4615 switch (break_policy_func (method)) {
4616 case MONO_BREAK_POLICY_ALWAYS:
4618 case MONO_BREAK_POLICY_NEVER:
4620 case MONO_BREAK_POLICY_ON_DBG:
4621 g_warning ("mdb no longer supported");
4624 g_warning ("Incorrect value returned from break policy callback");
4629 // Custom handlers currently only implemented by Windows.
4632 mono_runtime_install_custom_handlers (const char *handlers)
4638 mono_runtime_install_custom_handlers_usage (void)
4641 "Custom Handlers:\n"
4642 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4643 " separated list of available handlers to install.\n"
4645 "No handlers supported on current platform.\n");
4647 #endif /* HOST_WIN32 */