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) ||
894 ((obj->vtable->klass) == mono_class_get_appdomain_unloaded_exception_class () &&
895 mono_thread_info_current ()->runtime_thread)) {
898 mono_invoke_unhandled_exception_hook (obj);
903 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
905 MonoJitTlsData *jit_tls;
908 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
912 jit_tls = g_new0 (MonoJitTlsData, 1);
914 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
915 jit_tls->end_of_stack = stack_start;
917 mono_set_jit_tls (jit_tls);
919 lmf = g_new0 (MonoLMF, 1);
920 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
922 jit_tls->first_lmf = lmf;
924 mono_set_lmf_addr (&jit_tls->lmf);
928 #ifdef MONO_ARCH_HAVE_TLS_INIT
929 mono_arch_tls_init ();
932 mono_setup_altstack (jit_tls);
938 free_jit_tls_data (MonoJitTlsData *jit_tls)
940 mono_arch_free_jit_tls_data (jit_tls);
941 mono_free_altstack (jit_tls);
943 g_free (jit_tls->first_lmf);
948 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
950 MonoThreadInfo *thread;
951 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
952 thread = mono_thread_info_current_unchecked ();
954 thread->jit_data = jit_tls;
956 mono_arch_cpu_init ();
959 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
962 mono_thread_abort_dummy (MonoObject *obj)
964 if (mono_thread_attach_aborted_cb)
965 mono_thread_attach_aborted_cb (obj);
967 mono_thread_abort (obj);
971 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
973 MonoThreadInfo *thread;
974 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
975 thread = mono_thread_info_current_unchecked ();
977 thread->jit_data = jit_tls;
979 mono_arch_cpu_init ();
983 mini_thread_cleanup (MonoNativeThreadId tid)
985 MonoJitTlsData *jit_tls = NULL;
986 MonoThreadInfo *info;
988 info = mono_thread_info_current_unchecked ();
990 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
991 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
992 * not a trivial thing.
994 * The current offender is mono_thread_manage which cleanup threads from the outside.
996 if (info && mono_thread_info_get_tid (info) == tid) {
997 jit_tls = (MonoJitTlsData *)info->jit_data;
998 info->jit_data = NULL;
1000 mono_set_jit_tls (NULL);
1002 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1003 if (mono_get_lmf ()) {
1004 mono_set_lmf (NULL);
1005 mono_set_lmf_addr (NULL);
1008 info = mono_thread_info_lookup (tid);
1010 jit_tls = (MonoJitTlsData *)info->jit_data;
1011 info->jit_data = NULL;
1013 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1017 free_jit_tls_data (jit_tls);
1021 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1023 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1027 ji->data.target = target;
1033 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1035 static const char* const patch_info_str[] = {
1036 #define PATCH_INFO(a,b) "" #a,
1037 #include "patch-info.h"
1042 mono_ji_type_to_string (MonoJumpInfoType type)
1044 return patch_info_str [type];
1048 mono_print_ji (const MonoJumpInfo *ji)
1051 case MONO_PATCH_INFO_RGCTX_FETCH: {
1052 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1054 printf ("[RGCTX_FETCH ");
1055 mono_print_ji (entry->data);
1056 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1059 case MONO_PATCH_INFO_METHODCONST: {
1060 char *s = mono_method_full_name (ji->data.method, TRUE);
1061 printf ("[METHODCONST - %s]", s);
1065 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1066 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1070 printf ("[%s]", patch_info_str [ji->type]);
1078 mono_ji_type_to_string (MonoJumpInfoType type)
1084 mono_print_ji (const MonoJumpInfo *ji)
1091 * mono_patch_info_dup_mp:
1093 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1096 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1098 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1099 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1101 switch (patch_info->type) {
1102 case MONO_PATCH_INFO_RVA:
1103 case MONO_PATCH_INFO_LDSTR:
1104 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1105 case MONO_PATCH_INFO_LDTOKEN:
1106 case MONO_PATCH_INFO_DECLSEC:
1107 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1108 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1110 case MONO_PATCH_INFO_SWITCH:
1111 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1112 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1113 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1114 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1116 case MONO_PATCH_INFO_RGCTX_FETCH:
1117 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1118 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1119 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1120 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1122 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1123 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1124 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1126 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1127 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1128 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1130 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1131 MonoGSharedVtMethodInfo *info;
1132 MonoGSharedVtMethodInfo *oinfo;
1135 oinfo = patch_info->data.gsharedvt_method;
1136 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1137 res->data.gsharedvt_method = info;
1138 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1139 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1140 for (i = 0; i < oinfo->num_entries; ++i) {
1141 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1142 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1144 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1146 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1147 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1150 case MONO_PATCH_INFO_VIRT_METHOD: {
1151 MonoJumpInfoVirtMethod *info;
1152 MonoJumpInfoVirtMethod *oinfo;
1154 oinfo = patch_info->data.virt_method;
1155 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1156 res->data.virt_method = info;
1157 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1168 mono_patch_info_hash (gconstpointer data)
1170 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1173 case MONO_PATCH_INFO_RVA:
1174 case MONO_PATCH_INFO_LDSTR:
1175 case MONO_PATCH_INFO_LDTOKEN:
1176 case MONO_PATCH_INFO_DECLSEC:
1177 return (ji->type << 8) | ji->data.token->token;
1178 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1179 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1180 case MONO_PATCH_INFO_INTERNAL_METHOD:
1181 return (ji->type << 8) | g_str_hash (ji->data.name);
1182 case MONO_PATCH_INFO_VTABLE:
1183 case MONO_PATCH_INFO_CLASS:
1184 case MONO_PATCH_INFO_IID:
1185 case MONO_PATCH_INFO_ADJUSTED_IID:
1186 case MONO_PATCH_INFO_METHODCONST:
1187 case MONO_PATCH_INFO_METHOD:
1188 case MONO_PATCH_INFO_METHOD_JUMP:
1189 case MONO_PATCH_INFO_IMAGE:
1190 case MONO_PATCH_INFO_ICALL_ADDR:
1191 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1192 case MONO_PATCH_INFO_FIELD:
1193 case MONO_PATCH_INFO_SFLDA:
1194 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1195 case MONO_PATCH_INFO_METHOD_RGCTX:
1196 case MONO_PATCH_INFO_SIGNATURE:
1197 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1198 case MONO_PATCH_INFO_AOT_JIT_INFO:
1199 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1200 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1201 return (ji->type << 8) | (gssize)ji->data.target;
1202 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1203 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1204 case MONO_PATCH_INFO_RGCTX_FETCH:
1205 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1206 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1208 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1210 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1211 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1212 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1213 case MONO_PATCH_INFO_GC_NURSERY_START:
1214 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1215 case MONO_PATCH_INFO_GOT_OFFSET:
1216 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1217 case MONO_PATCH_INFO_AOT_MODULE:
1218 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1219 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1220 return (ji->type << 8);
1221 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1222 return (ji->type << 8) | (ji->data.index);
1223 case MONO_PATCH_INFO_SWITCH:
1224 return (ji->type << 8) | ji->data.table->table_size;
1225 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1226 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1227 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1228 /* Hash on the selector name */
1229 return g_str_hash (ji->data.target);
1230 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1231 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1232 case MONO_PATCH_INFO_LDSTR_LIT:
1233 return g_str_hash (ji->data.target);
1234 case MONO_PATCH_INFO_VIRT_METHOD: {
1235 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1237 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1239 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1240 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1241 return (ji->type << 8) | g_str_hash (ji->data.target);
1242 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1243 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1245 printf ("info type: %d\n", ji->type);
1246 mono_print_ji (ji); printf ("\n");
1247 g_assert_not_reached ();
1253 * mono_patch_info_equal:
1255 * This might fail to recognize equivalent patches, i.e. floats, so its only
1256 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1260 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1262 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1263 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1265 if (ji1->type != ji2->type)
1268 switch (ji1->type) {
1269 case MONO_PATCH_INFO_RVA:
1270 case MONO_PATCH_INFO_LDSTR:
1271 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1272 case MONO_PATCH_INFO_LDTOKEN:
1273 case MONO_PATCH_INFO_DECLSEC:
1274 if ((ji1->data.token->image != ji2->data.token->image) ||
1275 (ji1->data.token->token != ji2->data.token->token) ||
1276 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1277 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1278 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1281 case MONO_PATCH_INFO_INTERNAL_METHOD:
1282 return g_str_equal (ji1->data.name, ji2->data.name);
1283 case MONO_PATCH_INFO_RGCTX_FETCH:
1284 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1285 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1286 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1288 return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
1290 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1291 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1292 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1294 return c1->sig == c2->sig && c1->method == c2->method;
1296 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1297 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1298 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1299 return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->is_virtual == ji2->data.del_tramp->is_virtual;
1300 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1301 return ji1->data.index == ji2->data.index;
1302 case MONO_PATCH_INFO_VIRT_METHOD:
1303 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1304 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1305 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1306 if (ji1->data.target == ji2->data.target)
1308 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1309 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1310 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1312 if (ji1->data.target != ji2->data.target)
1321 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1323 unsigned char *ip = patch_info->ip.i + code;
1324 gconstpointer target = NULL;
1328 switch (patch_info->type) {
1329 case MONO_PATCH_INFO_BB:
1331 * FIXME: This could be hit for methods without a prolog. Should use -1
1332 * but too much code depends on a 0 initial value.
1334 //g_assert (patch_info->data.bb->native_offset);
1335 target = patch_info->data.bb->native_offset + code;
1337 case MONO_PATCH_INFO_ABS:
1338 target = patch_info->data.target;
1340 case MONO_PATCH_INFO_LABEL:
1341 target = patch_info->data.inst->inst_c0 + code;
1343 case MONO_PATCH_INFO_IP:
1346 case MONO_PATCH_INFO_METHOD_REL:
1347 target = code + patch_info->data.offset;
1349 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1350 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1352 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1353 g_assert_not_reached ();
1355 target = mono_icall_get_wrapper (mi);
1358 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1359 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1360 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1362 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1363 g_assert_not_reached ();
1368 case MONO_PATCH_INFO_METHOD_JUMP:
1369 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1370 if (!mono_error_ok (error))
1373 case MONO_PATCH_INFO_METHOD:
1374 if (patch_info->data.method == method) {
1377 /* get the trampoline to the method from the domain */
1378 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1379 if (!mono_error_ok (error))
1383 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1386 mono_domain_lock (domain);
1387 if (!domain_jit_info (domain)->method_code_hash)
1388 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1389 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1391 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1392 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1394 mono_domain_unlock (domain);
1398 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1399 g_assert (mono_threads_is_coop_enabled ());
1400 target = (gpointer)&mono_polling_required;
1402 case MONO_PATCH_INFO_SWITCH: {
1403 gpointer *jump_table;
1405 if (method && method->dynamic) {
1406 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1408 if (mono_aot_only) {
1409 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1411 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1415 for (i = 0; i < patch_info->data.table->table_size; i++) {
1416 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1419 target = jump_table;
1422 case MONO_PATCH_INFO_METHODCONST:
1423 case MONO_PATCH_INFO_CLASS:
1424 case MONO_PATCH_INFO_IMAGE:
1425 case MONO_PATCH_INFO_FIELD:
1426 case MONO_PATCH_INFO_SIGNATURE:
1427 case MONO_PATCH_INFO_AOT_MODULE:
1428 target = patch_info->data.target;
1430 case MONO_PATCH_INFO_IID:
1431 mono_class_init (patch_info->data.klass);
1432 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1434 case MONO_PATCH_INFO_ADJUSTED_IID:
1435 mono_class_init (patch_info->data.klass);
1436 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1438 case MONO_PATCH_INFO_VTABLE:
1439 target = mono_class_vtable (domain, patch_info->data.klass);
1442 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1443 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1445 if (del_tramp->is_virtual)
1446 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1448 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1451 case MONO_PATCH_INFO_SFLDA: {
1452 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1454 if (mono_class_field_is_special_static (patch_info->data.field)) {
1455 gpointer addr = NULL;
1457 mono_domain_lock (domain);
1458 if (domain->special_static_fields)
1459 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1460 mono_domain_unlock (domain);
1466 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1467 /* Done by the generated code */
1471 if (!mono_runtime_class_init_full (vtable, error)) {
1476 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1479 case MONO_PATCH_INFO_RVA: {
1480 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1483 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1484 target = mono_image_rva_map (patch_info->data.token->image, rva);
1487 case MONO_PATCH_INFO_R4:
1488 case MONO_PATCH_INFO_R8:
1489 target = patch_info->data.target;
1491 case MONO_PATCH_INFO_EXC_NAME:
1492 target = patch_info->data.name;
1494 case MONO_PATCH_INFO_LDSTR:
1496 mono_ldstr_checked (domain, patch_info->data.token->image,
1497 mono_metadata_token_index (patch_info->data.token->token), error);
1499 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1501 MonoClass *handle_class;
1503 handle = mono_ldtoken_checked (patch_info->data.token->image,
1504 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1505 if (!mono_error_ok (error))
1507 mono_class_init (handle_class);
1508 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1510 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1511 if (!mono_error_ok (error))
1515 case MONO_PATCH_INFO_LDTOKEN: {
1517 MonoClass *handle_class;
1519 handle = mono_ldtoken_checked (patch_info->data.token->image,
1520 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1521 if (!mono_error_ok (error))
1522 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1523 mono_class_init (handle_class);
1528 case MONO_PATCH_INFO_DECLSEC:
1529 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1531 case MONO_PATCH_INFO_ICALL_ADDR:
1532 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1533 /* run_cctors == 0 -> AOT */
1534 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1535 const char *exc_class;
1536 const char *exc_arg;
1539 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1541 if (mono_aot_only) {
1542 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1545 g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info->data.method, TRUE));
1551 target = mono_lookup_internal_call (patch_info->data.method);
1553 if (!target && run_cctors)
1554 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1557 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1558 target = mono_thread_interruption_request_flag ();
1560 case MONO_PATCH_INFO_METHOD_RGCTX: {
1561 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1564 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1567 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1568 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1570 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1573 case MONO_PATCH_INFO_BB_OVF:
1574 case MONO_PATCH_INFO_EXC_OVF:
1575 case MONO_PATCH_INFO_GOT_OFFSET:
1576 case MONO_PATCH_INFO_NONE:
1578 case MONO_PATCH_INFO_RGCTX_FETCH: {
1579 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1581 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1584 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1585 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1587 /* AOT, not needed */
1590 target = mono_arch_get_seq_point_info (domain, code);
1593 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1594 int card_table_shift_bits;
1595 gpointer card_table_mask;
1597 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1600 case MONO_PATCH_INFO_GC_NURSERY_START: {
1604 target = mono_gc_get_nursery (&shift_bits, &size);
1607 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1611 mono_gc_get_nursery (&shift_bits, &size);
1613 target = (gpointer)(mgreg_t)shift_bits;
1616 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1617 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1620 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1624 case MONO_PATCH_INFO_LDSTR_LIT: {
1628 len = strlen ((const char *)patch_info->data.target);
1629 s = (char *)mono_domain_alloc0 (domain, len + 1);
1630 memcpy (s, patch_info->data.target, len);
1635 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1636 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1638 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1639 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1641 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1642 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1644 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1645 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1650 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1651 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1655 g_assert_not_reached ();
1658 return (gpointer)target;
1662 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1664 MonoGenericInst *inst;
1667 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1669 if (context && context->class_inst) {
1670 inst = context->class_inst;
1671 for (i = 0; i < inst->type_argc; ++i) {
1672 MonoType *type = inst->type_argv [i];
1674 if (mini_is_gsharedvt_gparam (type))
1675 gsctx->is_gsharedvt = TRUE;
1678 if (context && context->method_inst) {
1679 inst = context->method_inst;
1681 for (i = 0; i < inst->type_argc; ++i) {
1682 MonoType *type = inst->type_argv [i];
1684 if (mini_is_gsharedvt_gparam (type))
1685 gsctx->is_gsharedvt = TRUE;
1691 * LOCKING: Acquires the jit code hash lock.
1694 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1697 static gboolean inited = FALSE;
1698 static int lookups = 0;
1699 static int failed_lookups = 0;
1701 mono_domain_jit_code_hash_lock (domain);
1702 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1703 if (!ji && shared) {
1704 /* Try generic sharing */
1705 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1706 if (ji && !ji->has_generic_jit_info)
1709 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1710 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1718 mono_domain_jit_code_hash_unlock (domain);
1724 lookup_method (MonoDomain *domain, MonoMethod *method)
1729 ji = mini_lookup_method (domain, method, NULL);
1732 if (!mono_method_is_generic_sharable (method, FALSE))
1734 shared = mini_get_shared_method (method);
1735 ji = mini_lookup_method (domain, method, shared);
1742 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1747 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1748 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1750 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
1751 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1754 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
1755 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1758 mono_class_init (klass);
1763 static FILE* perf_map_file;
1766 mono_enable_jit_map (void)
1768 if (!perf_map_file) {
1770 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1772 perf_map_file = fopen (name, "w");
1777 mono_emit_jit_tramp (void *start, int size, const char *desc)
1780 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1784 mono_emit_jit_map (MonoJitInfo *jinfo)
1786 if (perf_map_file) {
1787 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1788 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1794 mono_jit_map_is_enabled (void)
1796 return perf_map_file != NULL;
1802 no_gsharedvt_in_wrapper (void)
1804 g_assert_not_reached ();
1810 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.
1811 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1812 Dependency management in this case is too complex to justify implementing it.
1814 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1817 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1818 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1819 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1820 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1825 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1826 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1827 int threads_waiting; /* Number of threads waiting on this job */
1828 gboolean has_cond; /* True if @cond was initialized */
1829 gboolean done; /* True if the method finished JIT'ing */
1830 MonoCoopCond cond; /* Cond sleeping threads wait one */
1831 } JitCompilationEntry;
1834 GPtrArray *in_flight_methods; //JitCompilationEntry*
1836 } JitCompilationData;
1838 static JitCompilationData compilation_data;
1839 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1842 mini_jit_init_job_control (void)
1844 mono_coop_mutex_init (&compilation_data.lock);
1845 compilation_data.in_flight_methods = g_ptr_array_new ();
1849 lock_compilation_data (void)
1851 mono_coop_mutex_lock (&compilation_data.lock);
1855 unlock_compilation_data (void)
1857 mono_coop_mutex_unlock (&compilation_data.lock);
1860 static JitCompilationEntry*
1861 find_method (MonoMethod *method, MonoDomain *domain)
1864 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1865 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1866 if (e->method == method && e->domain == domain)
1874 add_current_thread (MonoJitTlsData *jit_tls)
1876 ++jit_tls->active_jit_methods;
1880 unref_jit_entry (JitCompilationEntry *entry)
1883 if (entry->ref_count)
1885 if (entry->has_cond)
1886 mono_coop_cond_destroy (&entry->cond);
1891 * Returns true if this method waited successfully for another thread to JIT it
1894 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1896 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1897 JitCompilationEntry *entry;
1899 static gboolean inited;
1901 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1902 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1903 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1904 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1908 lock_compilation_data ();
1910 if (!(entry = find_method (method, domain))) {
1911 entry = g_new0 (JitCompilationEntry, 1);
1912 entry->method = method;
1913 entry->domain = domain;
1914 entry->compilation_count = entry->ref_count = 1;
1915 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1916 g_assert (find_method (method, domain) == entry);
1917 add_current_thread (jit_tls);
1919 unlock_compilation_data ();
1921 } else if (jit_tls->active_jit_methods > 0) {
1922 //We can't suspend the current thread if it's already JITing a method.
1923 //Dependency management is too compilated and we want to get rid of this anyways.
1924 ++entry->compilation_count;
1925 ++jit_methods_multiple;
1926 ++jit_tls->active_jit_methods;
1928 unlock_compilation_data ();
1931 ++jit_methods_waited;
1934 if (!entry->has_cond) {
1935 mono_coop_cond_init (&entry->cond);
1936 entry->has_cond = TRUE;
1940 ++entry->threads_waiting;
1942 g_assert (entry->has_cond);
1943 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1944 --entry->threads_waiting;
1947 unref_jit_entry (entry);
1948 unlock_compilation_data ();
1951 ++jit_spurious_wakeups;
1958 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1960 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1962 lock_compilation_data ();
1964 g_assert (jit_tls->active_jit_methods > 0);
1965 --jit_tls->active_jit_methods;
1967 JitCompilationEntry *entry = find_method (method, target_domain);
1968 g_assert (entry); // It would be weird to fail
1971 if (entry->threads_waiting) {
1972 g_assert (entry->has_cond);
1973 mono_coop_cond_broadcast (&entry->cond);
1976 if (--entry->compilation_count == 0) {
1977 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1978 unref_jit_entry (entry);
1981 unlock_compilation_data ();
1986 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1988 MonoDomain *target_domain, *domain = mono_domain_get ();
1990 gpointer code = NULL, p;
1992 MonoJitICallInfo *callinfo = NULL;
1993 WrapperInfo *winfo = NULL;
1997 #ifdef ENABLE_INTERPRETER
1998 if (mono_use_interpreter && !jit_only) {
1999 code = mono_interp_create_method_pointer (method, error);
2006 /* Should be handled by the caller */
2007 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2010 * ICALL wrappers are handled specially, since there is only one copy of them
2011 * shared by all appdomains.
2013 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2014 winfo = mono_marshal_get_wrapper_info (method);
2015 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2016 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2017 g_assert (callinfo);
2019 /* Must be domain neutral since there is only one copy */
2020 opt |= MONO_OPT_SHARED;
2022 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2023 opt &= ~MONO_OPT_SHARED;
2026 if (opt & MONO_OPT_SHARED)
2027 target_domain = mono_get_root_domain ();
2029 target_domain = domain;
2031 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2032 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2035 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2036 MonoGenericContext *ctx = NULL;
2037 if (method->is_inflated)
2038 ctx = mono_method_get_context (method);
2039 method = info->d.synchronized_inner.method;
2041 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2042 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2048 info = lookup_method (target_domain, method);
2050 /* We can't use a domain specific method in another domain */
2051 if (! ((domain != target_domain) && !info->domain_neutral)) {
2054 InterlockedIncrement (&mono_jit_stats.methods_lookups);
2055 vtable = mono_class_vtable_full (domain, method->klass, error);
2059 if (!mono_runtime_class_init_full (vtable, error))
2061 return mono_create_ftnptr (target_domain, info->code_start);
2065 #ifdef MONO_USE_AOT_COMPILER
2066 if (opt & MONO_OPT_AOT) {
2067 MonoDomain *domain = NULL;
2069 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2070 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2072 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
2073 /* AOT'd wrappers for interp must be owned by root domain */
2074 domain = mono_get_root_domain ();
2078 domain = mono_domain_get ();
2080 mono_class_init (method->klass);
2082 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2085 if (mono_gc_is_critical_method (method)) {
2087 * The suspend code needs to be able to lookup these methods by ip in async context,
2088 * so preload their jit info.
2090 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2095 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2096 * This is not a problem, since it will be initialized when the method is first
2097 * called by init_method ().
2099 if (!mono_llvm_only) {
2100 vtable = mono_class_vtable (domain, method->klass);
2102 if (!mono_runtime_class_init_full (vtable, error))
2111 if (!code && mono_llvm_only) {
2112 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2113 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2115 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2117 * These wrappers are only created for signatures which are in the program, but
2118 * sometimes we load methods too eagerly and have to create them even if they
2119 * will never be called.
2121 return no_gsharedvt_in_wrapper;
2127 if (wait_or_register_method_to_compile (method, target_domain))
2129 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2130 unregister_method_for_compile (method, target_domain);
2132 if (!mono_error_ok (error))
2135 if (!code && mono_llvm_only) {
2136 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2137 g_assert_not_reached ();
2143 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2147 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2149 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2153 p = mono_create_ftnptr (target_domain, code);
2156 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2157 mono_loader_lock ();
2159 if (!callinfo->wrapper) {
2160 callinfo->wrapper = p;
2161 mono_register_jit_icall_wrapper (callinfo, p);
2164 mono_loader_unlock ();
2171 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2175 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2180 * mono_jit_compile_method_jit_only:
2182 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2185 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2189 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2193 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2195 invalidated_delegate_trampoline (char *desc)
2197 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2198 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2204 * mono_jit_free_method:
2206 * Free all memory allocated by the JIT for METHOD.
2209 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2211 MonoJitDynamicMethodInfo *ji;
2212 gboolean destroy = TRUE;
2213 GHashTableIter iter;
2214 MonoJumpList *jlist;
2216 g_assert (method->dynamic);
2218 mono_domain_lock (domain);
2219 ji = mono_dynamic_code_hash_lookup (domain, method);
2220 mono_domain_unlock (domain);
2225 mono_debug_remove_method (method, domain);
2226 mono_lldb_remove_method (domain, method, ji);
2228 mono_domain_lock (domain);
2229 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2230 mono_domain_jit_code_hash_lock (domain);
2231 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2232 mono_domain_jit_code_hash_unlock (domain);
2233 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2235 /* requires the domain lock - took above */
2236 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2238 /* Remove jump targets in this method */
2239 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2240 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2241 GSList *tmp, *remove;
2244 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2245 guint8 *ip = (guint8 *)tmp->data;
2247 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2248 remove = g_slist_prepend (remove, tmp);
2250 for (tmp = remove; tmp; tmp = tmp->next) {
2251 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2253 g_slist_free (remove);
2255 mono_domain_unlock (domain);
2257 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2258 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2260 * Instead of freeing the code, change it to call an error routine
2261 * so people can fix their code.
2263 char *type = mono_type_full_name (&method->klass->byval_arg);
2264 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2267 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2273 * This needs to be done before freeing code_mp, since the code address is the
2274 * key in the table, so if we free the code_mp first, another thread can grab the
2275 * same code address and replace our entry in the table.
2277 mono_jit_info_table_remove (domain, ji->ji);
2280 mono_code_manager_destroy (ji->code_mp);
2285 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2287 MonoDomain *target_domain;
2290 if (default_opt & MONO_OPT_SHARED)
2291 target_domain = mono_get_root_domain ();
2293 target_domain = domain;
2295 info = lookup_method (target_domain, method);
2297 /* We can't use a domain specific method in another domain */
2298 if (! ((domain != target_domain) && !info->domain_neutral)) {
2299 InterlockedIncrement (&mono_jit_stats.methods_lookups);
2302 return info->code_start;
2311 static guint32 bisect_opt = 0;
2312 static GHashTable *bisect_methods_hash = NULL;
2315 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2318 char method_name [2048];
2321 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2322 g_assert (bisect_methods_hash);
2324 file = fopen (method_list_filename, "r");
2327 while (fgets (method_name, sizeof (method_name), file)) {
2328 size_t len = strlen (method_name);
2330 g_assert (method_name [len - 1] == '\n');
2331 method_name [len - 1] = 0;
2332 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2334 g_assert (feof (file));
2337 gboolean mono_do_single_method_regression = FALSE;
2338 guint32 mono_single_method_regression_opt = 0;
2339 MonoMethod *mono_current_single_method;
2340 GSList *mono_single_method_list;
2341 GHashTable *mono_single_method_hash;
2344 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2348 if (bisect_methods_hash) {
2349 char *name = mono_method_full_name (method, TRUE);
2350 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2353 return default_opt | bisect_opt;
2355 if (!mono_do_single_method_regression)
2357 if (!mono_current_single_method) {
2358 if (!mono_single_method_hash)
2359 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2360 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2361 g_hash_table_insert (mono_single_method_hash, method, method);
2362 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2366 if (method == mono_current_single_method)
2367 return mono_single_method_regression_opt;
2372 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2374 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2379 gpointer compiled_method;
2380 gpointer runtime_invoke;
2382 MonoDynCallInfo *dyn_call_info;
2383 MonoClass *ret_box_class;
2384 MonoMethodSignature *sig;
2385 gboolean gsharedvt_invoke;
2386 gpointer *wrapper_arg;
2387 } RuntimeInvokeInfo;
2389 static RuntimeInvokeInfo*
2390 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2393 RuntimeInvokeInfo *info;
2395 info = g_new0 (RuntimeInvokeInfo, 1);
2396 info->compiled_method = compiled_method;
2397 if (mono_llvm_only && method->string_ctor)
2398 info->sig = mono_marshal_get_string_ctor_signature (method);
2400 info->sig = mono_method_signature (method);
2402 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2403 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2404 if (!mono_error_ok (error))
2406 g_assert (info->vtable);
2408 MonoMethodSignature *sig = info->sig;
2412 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2413 * in full-aot mode, so we use a slower, but more generic wrapper if
2414 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2416 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2417 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2418 gboolean supported = TRUE;
2421 if (method->string_ctor)
2422 sig = mono_marshal_get_string_ctor_signature (method);
2424 for (i = 0; i < sig->param_count; ++i) {
2425 MonoType *t = sig->params [i];
2427 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2431 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2435 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2439 ret_type = sig->ret;
2440 switch (ret_type->type) {
2441 case MONO_TYPE_VOID:
2453 case MONO_TYPE_BOOLEAN:
2454 case MONO_TYPE_CHAR:
2457 info->ret_box_class = mono_class_from_mono_type (ret_type);
2460 info->ret_box_class = mono_defaults.int_class;
2462 case MONO_TYPE_STRING:
2463 case MONO_TYPE_CLASS:
2464 case MONO_TYPE_ARRAY:
2465 case MONO_TYPE_SZARRAY:
2466 case MONO_TYPE_OBJECT:
2468 case MONO_TYPE_GENERICINST:
2469 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2470 info->ret_box_class = mono_class_from_mono_type (ret_type);
2472 case MONO_TYPE_VALUETYPE:
2473 info->ret_box_class = mono_class_from_mono_type (ret_type);
2476 g_assert_not_reached ();
2480 if (!info->dyn_call_info) {
2481 if (mono_llvm_only) {
2482 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2483 g_assert_not_reached ();
2485 info->gsharedvt_invoke = TRUE;
2486 if (!callee_gsharedvt) {
2487 /* Invoke a gsharedvt out wrapper instead */
2488 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2489 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2491 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2492 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2494 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2495 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2496 g_free (wrapper_sig);
2498 info->compiled_method = mono_jit_compile_method (wrapper, error);
2499 if (!mono_error_ok (error)) {
2504 /* Gsharedvt methods can be invoked the same way */
2505 /* The out wrapper has the same signature as the compiled gsharedvt method */
2506 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2508 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2510 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2511 g_free (wrapper_sig);
2514 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2515 if (!mono_error_ok (error)) {
2525 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2527 MonoMethodSignature *sig = info->sig;
2528 MonoDomain *domain = mono_domain_get ();
2529 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2531 gpointer retval_ptr;
2532 guint8 retval [256];
2533 gpointer *param_refs;
2538 g_assert (info->gsharedvt_invoke);
2541 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2542 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2543 * signatures, so we only have to generate runtime invoke wrappers for these
2545 * This code also handles invocation of gsharedvt methods directly, no
2546 * out wrappers are used in that case.
2548 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2549 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2552 * The runtime invoke wrappers expects pointers to primitive types, so have to
2556 args [pindex ++] = &obj;
2557 if (sig->ret->type != MONO_TYPE_VOID) {
2558 retval_ptr = (gpointer)&retval;
2559 args [pindex ++] = &retval_ptr;
2561 for (i = 0; i < sig->param_count; ++i) {
2562 MonoType *t = sig->params [i];
2564 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2565 MonoClass *klass = mono_class_from_mono_type (t);
2566 guint8 *nullable_buf;
2569 size = mono_class_value_size (klass, NULL);
2570 nullable_buf = g_alloca (size);
2571 g_assert (nullable_buf);
2573 /* The argument pointed to by params [i] is either a boxed vtype or null */
2574 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2575 params [i] = nullable_buf;
2578 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2579 param_refs [i] = params [i];
2580 params [i] = &(param_refs [i]);
2582 args [pindex ++] = ¶ms [i];
2584 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2585 args [pindex ++] = &info->wrapper_arg;
2587 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2589 runtime_invoke (NULL, args, exc, info->compiled_method);
2593 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2594 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2596 return *(MonoObject**)retval;
2600 * mono_jit_runtime_invoke:
2601 * \param method: the method to invoke
2602 * \param obj: this pointer
2603 * \param params: array of parameter values.
2604 * \param exc: Set to the exception raised in the managed method.
2605 * \param error: error or caught exception object
2606 * If \p exc is NULL, \p error is thrown instead.
2607 * If coop is enabled, \p exc argument is ignored -
2608 * all exceptions are caught and propagated through \p error
2611 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2613 MonoMethod *invoke, *callee;
2614 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2615 MonoDomain *domain = mono_domain_get ();
2616 MonoJitDomainInfo *domain_info;
2617 RuntimeInvokeInfo *info, *info2;
2618 MonoJitInfo *ji = NULL;
2619 gboolean callee_gsharedvt = FALSE;
2621 #ifdef ENABLE_INTERPRETER
2622 if (mono_use_interpreter)
2623 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2630 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2631 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2635 domain_info = domain_jit_info (domain);
2637 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2640 if (mono_security_core_clr_enabled ()) {
2642 * This might be redundant since mono_class_vtable () already does this,
2643 * but keep it just in case for moonlight.
2645 mono_class_setup_vtable (method->klass);
2646 if (mono_class_has_failure (method->klass)) {
2647 mono_error_set_for_class_failure (error, method->klass);
2649 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2654 gpointer compiled_method;
2657 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2658 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2660 * Array Get/Set/Address methods. The JIT implements them using inline code
2661 * inside the runtime invoke wrappers, so no need to compile them.
2663 if (mono_aot_only) {
2665 * Call a wrapper, since the runtime invoke wrapper was not generated.
2667 MonoMethod *wrapper;
2669 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2670 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2678 compiled_method = mono_jit_compile_method (callee, error);
2679 if (!compiled_method) {
2680 g_assert (!mono_error_ok (error));
2684 if (mono_llvm_only) {
2685 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2686 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2687 if (callee_gsharedvt)
2688 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2691 if (!callee_gsharedvt)
2692 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2694 compiled_method = NULL;
2697 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2698 if (!mono_error_ok (error))
2701 mono_domain_lock (domain);
2702 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2703 mono_domain_unlock (domain);
2711 * We need this here because mono_marshal_get_runtime_invoke can place
2712 * the helper method in System.Object and not the target class.
2714 if (!mono_runtime_class_init_full (info->vtable, error)) {
2716 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2720 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2721 we always catch the exception and propagate it through the MonoError */
2722 gboolean catchExcInMonoError =
2723 (exc == NULL) && mono_threads_is_coop_enabled ();
2724 MonoObject *invoke_exc = NULL;
2725 if (catchExcInMonoError)
2728 /* The wrappers expect this to be initialized to NULL */
2732 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2733 if (info->dyn_call_info) {
2734 MonoMethodSignature *sig = mono_method_signature (method);
2736 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2739 guint8 retval [256];
2741 if (!dyn_runtime_invoke) {
2742 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2743 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2744 if (!mono_error_ok (error))
2748 /* Convert the arguments to the format expected by start_dyn_call () */
2749 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2752 args [pindex ++] = &obj;
2753 for (i = 0; i < sig->param_count; ++i) {
2754 MonoType *t = sig->params [i];
2757 args [pindex ++] = ¶ms [i];
2758 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2759 args [pindex ++] = ¶ms [i];
2761 args [pindex ++] = params [i];
2765 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2767 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2769 dyn_runtime_invoke (buf, exc, info->compiled_method);
2770 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2772 if (catchExcInMonoError && *exc != NULL) {
2773 mono_error_set_exception_instance (error, (MonoException*) *exc);
2777 if (info->ret_box_class)
2778 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2780 return *(MonoObject**)retval;
2786 if (mono_llvm_only) {
2787 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2791 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2793 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2795 if (catchExcInMonoError && *exc != NULL)
2796 mono_error_set_exception_instance (error, (MonoException*) *exc);
2805 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2808 * mini_llvmonly_initial_imt_tramp:
2810 * This function is called the first time a call is made through an IMT trampoline.
2811 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2814 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2816 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2821 mono_vtable_build_imt_slot (info->vtable, info->slot);
2823 imt = (gpointer*)info->vtable;
2824 imt -= MONO_IMT_SIZE;
2826 /* Return what the real IMT trampoline returns */
2827 ftndesc = imt [info->slot];
2830 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2831 /* Happens when the imt slot contains only a generic virtual method */
2833 return func ((gpointer *)ftndesc [1], imt_method);
2836 /* This is called indirectly through an imt slot. */
2838 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2842 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2843 while (arg [i] && arg [i] != imt_method)
2850 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2852 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2854 //g_assert (arg [0] == imt_method);
2859 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2861 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2862 if (arg [0] == imt_method)
2869 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2871 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2872 if (arg [0] == imt_method)
2874 else if (arg [2] == imt_method)
2881 * A version of the imt trampoline used for generic virtual/variant iface methods.
2882 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2883 * in the search table. The original JIT code had a 'fallback' trampoline it could
2884 * call, but we can't do that, so we just return NULL, and the compiled code
2888 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2892 while (arg [i] && arg [i] != imt_method)
2901 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2905 int i, index, real_count;
2906 gboolean virtual_generic = FALSE;
2909 * Create an array which is passed to the imt trampoline functions.
2910 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2914 for (i = 0; i < count; ++i) {
2915 MonoIMTCheckItem *item = imt_entries [i];
2917 if (item->is_equals)
2919 if (item->has_target_code)
2920 virtual_generic = TRUE;
2924 * Initialize all vtable entries reachable from this imt slot, so the compiled
2925 * code doesn't have to check it.
2927 for (i = 0; i < count; ++i) {
2928 MonoIMTCheckItem *item = imt_entries [i];
2931 if (!item->is_equals || item->has_target_code)
2933 vt_slot = item->value.vtable_slot;
2934 mono_init_vtable_slot (vtable, vt_slot);
2937 /* Save the entries into an array */
2938 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2940 for (i = 0; i < count; ++i) {
2941 MonoIMTCheckItem *item = imt_entries [i];
2943 if (!item->is_equals)
2946 g_assert (item->key);
2947 buf [(index * 2)] = item->key;
2948 if (item->has_target_code)
2949 buf [(index * 2) + 1] = item->value.target_code;
2951 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2954 buf [(index * 2)] = NULL;
2955 buf [(index * 2) + 1] = fail_tramp;
2958 * Return a function descriptor for a C function with 'buf' as its argument.
2959 * It will by called by JITted code.
2961 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2962 switch (real_count) {
2964 res [0] = mono_llvmonly_imt_tramp_1;
2967 res [0] = mono_llvmonly_imt_tramp_2;
2970 res [0] = mono_llvmonly_imt_tramp_3;
2973 res [0] = mono_llvmonly_imt_tramp;
2976 if (virtual_generic || fail_tramp)
2977 res [0] = mono_llvmonly_fallback_imt_tramp;
2983 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2985 MonoException *exc = NULL;
2987 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2988 MONO_SIG_HANDLER_GET_CONTEXT;
2990 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2992 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2994 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2995 if (mono_arch_is_int_overflow (ctx, info))
2997 * The spec says this throws ArithmeticException, but MS throws the derived
2998 * OverflowException.
3000 exc = mono_get_exception_overflow ();
3002 exc = mono_get_exception_divide_by_zero ();
3004 exc = mono_get_exception_divide_by_zero ();
3008 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3011 mono_handle_native_crash ("SIGFPE", ctx, info);
3012 if (mono_do_crash_chaining) {
3013 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3018 mono_arch_handle_exception (ctx, exc);
3021 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3024 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3026 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3027 MONO_SIG_HANDLER_GET_CONTEXT;
3029 if (mono_runtime_get_no_exec ())
3033 mono_handle_native_crash ("SIGILL", ctx, info);
3034 if (mono_do_crash_chaining) {
3035 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3039 g_assert_not_reached ();
3042 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3043 #define HAVE_SIG_INFO
3046 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3049 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3050 gpointer fault_addr = NULL;
3051 #ifdef HAVE_SIG_INFO
3052 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3056 MONO_SIG_HANDLER_GET_CONTEXT;
3058 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3059 if (mono_arch_is_single_step_event (info, ctx)) {
3060 mono_debugger_agent_single_step_event (ctx);
3062 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3063 mono_debugger_agent_breakpoint_hit (ctx);
3068 #if defined(HAVE_SIG_INFO)
3069 #if !defined(HOST_WIN32)
3070 fault_addr = info->si_addr;
3071 if (mono_aot_is_pagefault (info->si_addr)) {
3072 mono_aot_handle_pagefault (info->si_addr);
3077 /* The thread might no be registered with the runtime */
3078 if (!mono_domain_get () || !jit_tls) {
3079 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3081 mono_handle_native_crash ("SIGSEGV", ctx, info);
3082 if (mono_do_crash_chaining) {
3083 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3089 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3091 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3092 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3095 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3096 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3097 fault_addr = info->si_addr;
3098 if (fault_addr == NULL) {
3101 mono_sigctx_to_monoctx (ctx, &mctx);
3103 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3107 if (jit_tls->stack_size &&
3108 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3110 * The hard-guard page has been hit: there is not much we can do anymore
3111 * Print a hopefully clear message and abort.
3113 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3114 g_assert_not_reached ();
3116 /* The original handler might not like that it is executed on an altstack... */
3117 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3120 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3125 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3128 mono_handle_native_crash ("SIGSEGV", ctx, info);
3130 if (mono_do_crash_chaining) {
3131 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3136 mono_arch_handle_exception (ctx, NULL);
3140 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3143 MONO_SIG_HANDLER_GET_CONTEXT;
3145 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3147 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3149 mono_arch_handle_exception (ctx, exc);
3151 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3154 #ifndef DISABLE_REMOTING
3155 /* mono_jit_create_remoting_trampoline:
3156 * @method: pointer to the method info
3158 * Creates a trampoline which calls the remoting functions. This
3159 * is used in the vtable of transparent proxies.
3161 * Returns: a pointer to the newly created code
3164 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3167 guint8 *addr = NULL;
3171 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3172 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3176 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3177 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3178 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3181 addr = (guint8 *)mono_compile_method_checked (nm, error);
3182 return_val_if_nok (error, NULL);
3183 return mono_get_addr_from_ftnptr (addr);
3187 static G_GNUC_UNUSED void
3188 no_imt_trampoline (void)
3190 g_assert_not_reached ();
3193 static G_GNUC_UNUSED void
3194 no_vcall_trampoline (void)
3196 g_assert_not_reached ();
3199 static gpointer *vtable_trampolines;
3200 static int vtable_trampolines_size;
3203 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3205 int index = slot_index + MONO_IMT_SIZE;
3207 if (mono_llvm_only) {
3208 if (slot_index < 0) {
3209 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3210 // FIXME: Memory management
3211 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3212 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3215 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3217 mono_memory_barrier ();
3224 g_assert (slot_index >= - MONO_IMT_SIZE);
3225 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3227 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3231 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3232 while (new_size <= index)
3234 new_table = g_new0 (gpointer, new_size);
3236 if (vtable_trampolines)
3237 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3238 g_free (vtable_trampolines);
3239 mono_memory_barrier ();
3240 vtable_trampolines = (void **)new_table;
3241 vtable_trampolines_size = new_size;
3246 if (!vtable_trampolines [index])
3247 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3248 return vtable_trampolines [index];
3252 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3254 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3258 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3263 gpointer *imt = (gpointer*)vt;
3264 imt -= MONO_IMT_SIZE;
3266 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3270 is_callee_gsharedvt_variable (gpointer addr)
3273 gboolean callee_gsharedvt;
3275 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3277 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3278 if (callee_gsharedvt)
3279 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3280 return callee_gsharedvt;
3284 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3286 gpointer arg = NULL;
3288 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3289 arg = mini_method_get_rgctx (method);
3292 * Avoid adding gsharedvt in wrappers since they might not exist if
3293 * this delegate is called through a gsharedvt delegate invoke wrapper.
3294 * Instead, encode that the method is gsharedvt in del->extra_arg,
3295 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3297 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3298 g_assert ((((mgreg_t)arg) & 1) == 0);
3299 arg = (gpointer)(((mgreg_t)arg) | 1);
3305 mini_init_delegate (MonoDelegate *del)
3308 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3309 #ifdef ENABLE_INTERPRETER
3310 if (mono_use_interpreter)
3311 mono_interp_init_delegate (del);
3316 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3320 abs_offset = offset;
3322 abs_offset = - abs_offset;
3323 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3327 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3329 gboolean is_virtual_generic, is_interface, load_imt_reg;
3332 static guint8 **cache = NULL;
3333 static int cache_size = 0;
3338 if (MONO_TYPE_ISSTRUCT (sig->ret))
3341 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3342 is_interface = mono_class_is_interface (method->klass);
3343 load_imt_reg = is_virtual_generic || is_interface;
3346 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3348 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3350 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3351 g_assert (idx >= 0);
3353 /* Resize the cache to idx + 1 */
3354 if (cache_size < idx + 1) {
3356 if (cache_size < idx + 1) {
3358 int new_cache_size = idx + 1;
3360 new_cache = g_new0 (guint8*, new_cache_size);
3362 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3365 mono_memory_barrier ();
3367 cache_size = new_cache_size;
3375 /* FIXME Support more cases */
3376 if (mono_aot_only) {
3377 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3378 g_assert (cache [idx]);
3380 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3386 * mini_parse_debug_option:
3387 * @option: The option to parse.
3389 * Parses debug options for the mono runtime. The options are the same as for
3390 * the MONO_DEBUG environment variable.
3394 mini_parse_debug_option (const char *option)
3396 if (!strcmp (option, "handle-sigint"))
3397 debug_options.handle_sigint = TRUE;
3398 else if (!strcmp (option, "keep-delegates"))
3399 debug_options.keep_delegates = TRUE;
3400 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3401 debug_options.reverse_pinvoke_exceptions = TRUE;
3402 else if (!strcmp (option, "collect-pagefault-stats"))
3403 debug_options.collect_pagefault_stats = TRUE;
3404 else if (!strcmp (option, "break-on-unverified"))
3405 debug_options.break_on_unverified = TRUE;
3406 else if (!strcmp (option, "no-gdb-backtrace"))
3407 debug_options.no_gdb_backtrace = TRUE;
3408 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3409 debug_options.suspend_on_native_crash = TRUE;
3410 else if (!strcmp (option, "suspend-on-exception"))
3411 debug_options.suspend_on_exception = TRUE;
3412 else if (!strcmp (option, "suspend-on-unhandled"))
3413 debug_options.suspend_on_unhandled = TRUE;
3414 else if (!strcmp (option, "dont-free-domains"))
3415 mono_dont_free_domains = TRUE;
3416 else if (!strcmp (option, "dyn-runtime-invoke"))
3417 debug_options.dyn_runtime_invoke = TRUE;
3418 else if (!strcmp (option, "gdb"))
3419 debug_options.gdb = TRUE;
3420 else if (!strcmp (option, "lldb"))
3421 debug_options.lldb = TRUE;
3422 else if (!strcmp (option, "explicit-null-checks"))
3423 debug_options.explicit_null_checks = TRUE;
3424 else if (!strcmp (option, "gen-seq-points"))
3425 debug_options.gen_sdb_seq_points = TRUE;
3426 else if (!strcmp (option, "gen-compact-seq-points"))
3427 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3428 else if (!strcmp (option, "no-compact-seq-points"))
3429 debug_options.no_seq_points_compact_data = TRUE;
3430 else if (!strcmp (option, "single-imm-size"))
3431 debug_options.single_imm_size = TRUE;
3432 else if (!strcmp (option, "init-stacks"))
3433 debug_options.init_stacks = TRUE;
3434 else if (!strcmp (option, "casts"))
3435 debug_options.better_cast_details = TRUE;
3436 else if (!strcmp (option, "soft-breakpoints"))
3437 debug_options.soft_breakpoints = TRUE;
3438 else if (!strcmp (option, "check-pinvoke-callconv"))
3439 debug_options.check_pinvoke_callconv = TRUE;
3440 else if (!strcmp (option, "use-fallback-tls"))
3441 debug_options.use_fallback_tls = TRUE;
3442 else if (!strcmp (option, "debug-domain-unload"))
3443 mono_enable_debug_domain_unload (TRUE);
3444 else if (!strcmp (option, "partial-sharing"))
3445 mono_set_partial_sharing_supported (TRUE);
3446 else if (!strcmp (option, "align-small-structs"))
3447 mono_align_small_structs = TRUE;
3448 else if (!strcmp (option, "native-debugger-break"))
3449 debug_options.native_debugger_break = TRUE;
3450 else if (!strcmp (option, "disable_omit_fp"))
3451 debug_options.disable_omit_fp = TRUE;
3459 mini_parse_debug_options (void)
3461 char *options = g_getenv ("MONO_DEBUG");
3462 gchar **args, **ptr;
3467 args = g_strsplit (options, ",", -1);
3470 for (ptr = args; ptr && *ptr; ptr++) {
3471 const char *arg = *ptr;
3473 if (!mini_parse_debug_option (arg)) {
3474 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3475 fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
3484 mini_get_debug_options (void)
3486 return &debug_options;
3490 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3492 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3495 gpointer* desc = NULL;
3497 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3499 # if defined(__ppc64__) || defined(__powerpc64__)
3501 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3507 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3513 mini_get_addr_from_ftnptr (gpointer descr)
3515 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3516 return *(gpointer*)descr;
3523 register_jit_stats (void)
3525 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3526 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3527 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3528 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3529 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3530 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3531 mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
3532 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3533 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3534 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3535 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3536 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3537 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3538 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3539 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3540 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3541 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3542 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3543 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3544 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3545 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3546 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3547 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3548 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3549 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3550 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3551 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3552 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3553 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3554 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3555 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3556 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3557 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3558 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3559 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3560 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3561 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3562 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3563 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3564 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3565 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3566 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3567 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3568 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3569 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3570 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3571 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3572 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3573 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3574 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3575 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3576 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3577 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3578 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3579 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3580 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3581 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3582 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3583 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3584 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3585 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3588 static void runtime_invoke_info_free (gpointer value);
3591 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3593 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3594 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3596 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3600 class_method_pair_hash (gconstpointer data)
3602 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3604 return (gsize)pair->klass ^ (gsize)pair->method;
3608 mini_create_jit_domain_info (MonoDomain *domain)
3610 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3612 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3613 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3614 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3615 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3616 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3617 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3618 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3619 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3620 mono_jit_code_hash_init (&info->interp_code_hash);
3622 domain->runtime_info = info;
3626 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3628 MonoJumpList *jlist = (MonoJumpList *)value;
3629 g_slist_free (jlist->list);
3633 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3635 GSList *list = (GSList *)value;
3636 g_slist_free (list);
3640 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3642 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3643 mono_code_manager_destroy (di->code_mp);
3648 runtime_invoke_info_free (gpointer value)
3650 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3652 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3653 if (info->dyn_call_info)
3654 mono_arch_dyn_call_free (info->dyn_call_info);
3660 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3662 g_slist_free (value);
3666 mini_free_jit_domain_info (MonoDomain *domain)
3668 MonoJitDomainInfo *info = domain_jit_info (domain);
3670 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3671 g_hash_table_destroy (info->jump_target_hash);
3672 if (info->jump_target_got_slot_hash) {
3673 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3674 g_hash_table_destroy (info->jump_target_got_slot_hash);
3676 if (info->dynamic_code_hash) {
3677 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3678 g_hash_table_destroy (info->dynamic_code_hash);
3680 if (info->method_code_hash)
3681 g_hash_table_destroy (info->method_code_hash);
3682 g_hash_table_destroy (info->jump_trampoline_hash);
3683 g_hash_table_destroy (info->jit_trampoline_hash);
3684 g_hash_table_destroy (info->delegate_trampoline_hash);
3685 if (info->static_rgctx_trampoline_hash)
3686 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3687 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3688 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3689 g_hash_table_destroy (info->seq_points);
3690 g_hash_table_destroy (info->arch_seq_points);
3691 if (info->agent_info)
3692 mono_debugger_agent_free_domain_info (domain);
3693 if (info->gsharedvt_arg_tramp_hash)
3694 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3695 if (info->llvm_jit_callees) {
3696 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3697 g_hash_table_destroy (info->llvm_jit_callees);
3699 mono_internal_hash_table_destroy (&info->interp_code_hash);
3701 mono_llvm_free_domain_info (domain);
3704 g_free (domain->runtime_info);
3705 domain->runtime_info = NULL;
3708 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3711 code_manager_chunk_new (void *chunk, int size)
3713 mono_arch_code_chunk_new (chunk, size);
3717 code_manager_chunk_destroy (void *chunk)
3719 mono_arch_code_chunk_destroy (chunk);
3726 llvm_init_inner (void)
3728 if (!mono_llvm_load (NULL))
3739 * Load and initialize LLVM support.
3740 * Return TRUE on success.
3743 mini_llvm_init (void)
3746 static gboolean llvm_inited;
3747 static gboolean init_result;
3749 mono_loader_lock_if_inited ();
3751 init_result = llvm_init_inner ();
3754 mono_loader_unlock_if_inited ();
3762 mini_add_profiler_argument (const char *desc)
3764 if (!profile_options)
3765 profile_options = g_ptr_array_new ();
3767 g_ptr_array_add (profile_options, (gpointer) desc);
3771 mini_init (const char *filename, const char *runtime_version)
3775 MonoRuntimeCallbacks callbacks;
3776 MonoThreadInfoRuntimeCallbacks ticallbacks;
3777 MonoCodeManagerCallbacks code_manager_callbacks;
3779 MONO_VES_INIT_BEGIN ();
3781 CHECKED_MONO_INIT ();
3783 #if defined(__linux__)
3784 if (access ("/proc/self/maps", F_OK) != 0) {
3785 g_print ("Mono requires /proc to be mounted.\n");
3790 #ifdef ENABLE_INTERPRETER
3791 mono_interp_init ();
3794 mono_os_mutex_init_recursive (&jit_mutex);
3796 mono_cross_helpers_run ();
3798 mono_counters_init ();
3802 mini_jit_init_job_control ();
3804 /* Happens when using the embedding interface */
3805 if (!default_opt_set)
3806 default_opt = mono_parse_default_optimizations (NULL);
3808 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3810 mono_set_generic_sharing_vt_supported (TRUE);
3813 mono_set_generic_sharing_vt_supported (TRUE);
3816 mono_tls_init_runtime_keys ();
3818 if (!global_codeman)
3819 global_codeman = mono_code_manager_new ();
3821 memset (&callbacks, 0, sizeof (callbacks));
3822 callbacks.create_ftnptr = mini_create_ftnptr;
3823 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3824 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3825 callbacks.set_cast_details = mono_set_cast_details;
3826 callbacks.debug_log = mono_debugger_agent_debug_log;
3827 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3828 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3829 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3830 callbacks.imt_entry_inited = mini_imt_entry_inited;
3831 callbacks.init_delegate = mini_init_delegate;
3832 #define JIT_INVOKE_WORKS
3833 #ifdef JIT_INVOKE_WORKS
3834 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3836 #define JIT_TRAMPOLINES_WORK
3837 #ifdef JIT_TRAMPOLINES_WORK
3838 callbacks.compile_method = mono_jit_compile_method;
3839 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3840 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3841 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3842 callbacks.free_method = mono_jit_free_method;
3843 #ifndef DISABLE_REMOTING
3844 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3848 mono_install_callbacks (&callbacks);
3850 memset (&ticallbacks, 0, sizeof (ticallbacks));
3851 ticallbacks.setup_async_callback = mono_setup_async_callback;
3852 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3853 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3854 ticallbacks.thread_state_init = mono_thread_state_init;
3857 mono_w32handle_init ();
3860 mono_thread_info_runtime_init (&ticallbacks);
3862 if (g_hasenv ("MONO_DEBUG")) {
3863 mini_parse_debug_options ();
3866 mono_code_manager_init ();
3868 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3869 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3870 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3871 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3873 mono_code_manager_install_callbacks (&code_manager_callbacks);
3877 mono_arch_cpu_init ();
3881 mono_unwind_init ();
3883 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3884 mono_lldb_init ("");
3885 mono_dont_free_domains = TRUE;
3888 #ifdef XDEBUG_ENABLED
3889 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3891 mono_xdebug_init (mono_xdebug);
3892 g_free (mono_xdebug);
3893 /* So methods for multiple domains don't have the same address */
3894 mono_dont_free_domains = TRUE;
3895 mono_using_xdebug = TRUE;
3896 } else if (mini_get_debug_options ()->gdb) {
3897 mono_xdebug_init ((char*)"gdb");
3898 mono_dont_free_domains = TRUE;
3899 mono_using_xdebug = TRUE;
3904 if (mono_use_llvm) {
3905 if (!mono_llvm_load (NULL)) {
3906 mono_use_llvm = FALSE;
3907 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3914 mono_trampolines_init ();
3916 if (default_opt & MONO_OPT_AOT)
3919 mono_debugger_agent_init ();
3921 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3922 mono_set_generic_sharing_supported (TRUE);
3925 mono_thread_info_signals_init ();
3927 #ifndef MONO_CROSS_COMPILE
3928 mono_runtime_install_handlers ();
3930 mono_threads_install_cleanup (mini_thread_cleanup);
3932 #ifdef JIT_TRAMPOLINES_WORK
3933 mono_install_create_domain_hook (mini_create_jit_domain_info);
3934 mono_install_free_domain_hook (mini_free_jit_domain_info);
3936 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3937 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3938 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3940 mono_profiler_state.context_enable = mini_profiler_context_enable;
3941 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
3942 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
3943 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
3944 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
3945 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
3947 if (profile_options)
3948 for (guint i = 0; i < profile_options->len; i++)
3949 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
3951 mono_profiler_started ();
3953 if (debug_options.collect_pagefault_stats)
3954 mono_aot_set_make_unreadable (TRUE);
3956 if (runtime_version)
3957 domain = mono_init_version (filename, runtime_version);
3959 domain = mono_init_from_assembly (filename, filename);
3961 if (mono_aot_only) {
3962 /* This helps catch code allocation requests */
3963 mono_code_manager_set_read_only (domain->code_mp);
3964 mono_marshal_use_aot_wrappers (TRUE);
3967 if (mono_llvm_only) {
3968 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3969 mono_set_always_build_imt_trampolines (TRUE);
3970 } else if (mono_aot_only) {
3971 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3973 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3976 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3977 mono_arch_finish_init ();
3981 /* This must come after mono_init () in the aot-only case */
3982 mono_exceptions_init ();
3984 /* This should come after mono_init () too */
3988 mono_create_helper_signatures ();
3991 register_jit_stats ();
3993 #define JIT_CALLS_WORK
3994 #ifdef JIT_CALLS_WORK
3995 /* Needs to be called here since register_jit_icall depends on it */
3996 mono_marshal_init ();
3998 mono_arch_register_lowlevel_calls ();
4002 mono_generic_sharing_init ();
4005 #ifdef MONO_ARCH_SIMD_INTRINSICS
4006 mono_simd_intrinsics_init ();
4009 mono_tasklets_init ();
4011 register_trampolines (domain);
4013 if (mono_compile_aot)
4015 * Avoid running managed code when AOT compiling, since the platform
4016 * might only support aot-only execution.
4018 mono_runtime_set_no_exec (TRUE);
4020 mono_mem_account_register_counters ();
4022 #define JIT_RUNTIME_WORKS
4023 #ifdef JIT_RUNTIME_WORKS
4024 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4025 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4026 mono_error_assert_ok (&error);
4027 mono_thread_attach (domain);
4028 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4031 if (mono_profiler_sampling_enabled ())
4032 mono_runtime_setup_stat_profiler ();
4034 MONO_PROFILER_RAISE (runtime_initialized, ());
4036 MONO_VES_INIT_END ();
4042 register_icalls (void)
4044 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4045 ves_icall_get_frame_info);
4046 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4047 ves_icall_get_trace);
4048 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4049 mono_runtime_install_handlers);
4050 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4051 mono_runtime_cleanup_handlers);
4053 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4054 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4055 mono_debugger_agent_unhandled_exception);
4059 * It's important that we pass `TRUE` as the last argument here, as
4060 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4061 * *did* emit a wrapper, we'd be looking at infinite recursion since
4062 * the wrapper would call the icall which would call the wrapper and
4065 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4066 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4067 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4069 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4070 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4071 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4072 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4073 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4074 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4076 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4077 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4078 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4079 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4080 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4081 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4082 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4083 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4084 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4086 // FIXME: This is broken
4087 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4090 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4091 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4092 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4093 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4094 register_icall (mono_thread_self_abort, "mono_thread_self_abort", "void", FALSE);
4095 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4096 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4098 if (mono_threads_is_coop_enabled ())
4099 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4101 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4102 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4103 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4104 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4105 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4106 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4108 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4109 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4110 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4113 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4114 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4115 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4116 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4119 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4120 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4121 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4122 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4123 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4126 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4127 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4130 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4131 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4132 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4135 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4136 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4139 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4140 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4141 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4142 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4143 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4144 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4145 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4148 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4149 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4150 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4153 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4154 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);
4156 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4157 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4159 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4160 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4162 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4163 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);
4165 #ifdef MONO_ARCH_EMULATE_FREM
4166 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4167 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4170 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4171 if (mono_arch_is_soft_float ()) {
4172 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4173 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4174 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4175 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4176 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4177 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4178 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4179 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4180 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4181 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4182 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4183 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4185 #if SIZEOF_VOID_P == 4
4186 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4189 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4190 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4191 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4192 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4193 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4194 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4195 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4196 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4197 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4198 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4200 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4201 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4202 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4203 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4204 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4206 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4207 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4208 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4209 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4212 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4214 #ifdef COMPRESSED_INTERFACE_BITMAP
4215 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4218 #if SIZEOF_REGISTER == 4
4219 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4221 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4224 /* other jit icalls */
4225 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4226 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4227 "ptr ptr ptr", FALSE);
4228 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4229 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4230 "ptr ptr ptr ptr", FALSE);
4231 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4232 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4233 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4234 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4235 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4236 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4237 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4238 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4239 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4240 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4241 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4242 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4243 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4244 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4245 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4246 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4247 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4248 register_icall (mono_break, "mono_break", NULL, TRUE);
4249 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4250 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4251 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4252 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4253 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4254 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4255 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4256 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4257 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4258 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4259 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4261 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4262 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4264 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4265 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4266 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4267 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4268 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4270 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4272 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4273 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4274 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4275 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4277 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4278 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4279 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4280 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4281 /* This needs a wrapper so it can have a preserveall cconv */
4282 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4283 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4284 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4285 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4286 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4287 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4288 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4290 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4291 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4292 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4293 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4296 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4298 /* Register tls icalls */
4299 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4300 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4301 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4302 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4303 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4304 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4305 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4306 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4307 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4308 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4311 MonoJitStats mono_jit_stats = {0};
4314 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4315 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4317 MONO_NO_SANITIZE_THREAD
4319 print_jit_stats (void)
4321 if (mono_jit_stats.enabled) {
4322 g_print ("Mono Jit statistics\n");
4323 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4324 mono_jit_stats.max_ratio_method);
4325 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4326 mono_jit_stats.biggest_method);
4328 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4329 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4330 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4331 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4332 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4333 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4334 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4335 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4337 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4338 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4339 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4341 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4342 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4343 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4344 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4346 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4347 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4348 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4349 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4350 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4351 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4352 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4353 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4355 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4356 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4357 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4359 g_free (mono_jit_stats.max_ratio_method);
4360 mono_jit_stats.max_ratio_method = NULL;
4361 g_free (mono_jit_stats.biggest_method);
4362 mono_jit_stats.biggest_method = NULL;
4367 mini_cleanup (MonoDomain *domain)
4369 if (mono_profiler_sampling_enabled ())
4370 mono_runtime_shutdown_stat_profiler ();
4372 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4375 cominterop_release_all_rcws ();
4378 #ifndef MONO_CROSS_COMPILE
4380 * mono_domain_finalize () needs to be called early since it needs the
4381 * execution engine still fully working (it may invoke managed finalizers).
4383 mono_domain_finalize (domain, 2000);
4386 /* This accesses metadata so needs to be called before runtime shutdown */
4389 #ifndef MONO_CROSS_COMPILE
4390 mono_runtime_cleanup (domain);
4393 mono_threadpool_cleanup ();
4395 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4397 mono_profiler_cleanup ();
4399 if (profile_options)
4400 g_ptr_array_free (profile_options, TRUE);
4402 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4404 mono_icall_cleanup ();
4406 mono_runtime_cleanup_handlers ();
4408 #ifndef MONO_CROSS_COMPILE
4409 mono_domain_free (domain, TRUE);
4414 mono_llvm_cleanup ();
4417 mono_aot_cleanup ();
4419 mono_trampolines_cleanup ();
4421 mono_unwind_cleanup ();
4423 mono_code_manager_destroy (global_codeman);
4424 g_free (vtable_trampolines);
4426 mini_jit_cleanup ();
4428 mono_tramp_info_cleanup ();
4430 mono_arch_cleanup ();
4432 mono_generic_sharing_cleanup ();
4436 mono_trace_cleanup ();
4438 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4440 if (mono_inject_async_exc_method)
4441 mono_method_desc_free (mono_inject_async_exc_method);
4443 mono_tls_free_keys ();
4445 mono_os_mutex_destroy (&jit_mutex);
4447 mono_code_manager_cleanup ();
4450 mono_w32handle_cleanup ();
4455 mono_set_defaults (int verbose_level, guint32 opts)
4457 mini_verbose = verbose_level;
4458 mono_set_optimizations (opts);
4462 mono_disable_optimizations (guint32 opts)
4464 default_opt &= ~opts;
4468 mono_set_optimizations (guint32 opts)
4471 default_opt_set = TRUE;
4472 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4473 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4476 mono_set_generic_sharing_vt_supported (TRUE);
4481 mono_set_verbose_level (guint32 level)
4483 mini_verbose = level;
4487 * mono_get_runtime_build_info:
4488 * The returned string is owned by the caller. The returned string
4489 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4490 * \returns the runtime version + build date in string format.
4493 mono_get_runtime_build_info (void)
4495 if (mono_build_date)
4496 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4498 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4502 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4504 GHashTable *assemblies = (GHashTable*)user_data;
4505 MonoImage *image = mono_assembly_get_image (ass);
4506 MonoMethod *method, *invoke;
4509 if (g_hash_table_lookup (assemblies, ass))
4512 g_hash_table_insert (assemblies, ass, ass);
4514 if (mini_verbose > 0)
4515 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4517 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4520 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4522 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4525 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4527 if (method->is_generic || mono_class_is_gtd (method->klass))
4531 if (mini_verbose > 1) {
4532 char * desc = mono_method_full_name (method, TRUE);
4533 g_print ("Compiling %d %s\n", count, desc);
4536 mono_compile_method_checked (method, &error);
4537 if (!is_ok (&error)) {
4538 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4541 if (strcmp (method->name, "Finalize") == 0) {
4542 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4543 mono_compile_method_checked (invoke, &error);
4544 mono_error_assert_ok (&error);
4546 #ifndef DISABLE_REMOTING
4547 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4548 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4549 mono_compile_method_checked (invoke, &error);
4550 mono_error_assert_ok (&error);
4555 /* Load and precompile referenced assemblies as well */
4556 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4557 mono_assembly_load_reference (image, i);
4558 if (image->references [i])
4559 mono_precompile_assembly (image->references [i], assemblies);
4563 void mono_precompile_assemblies ()
4565 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4567 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4569 g_hash_table_destroy (assemblies);
4574 * Have to export this for AOT.
4577 mono_personality (void)
4580 g_assert_not_reached ();
4584 static MonoBreakPolicy
4585 always_insert_breakpoint (MonoMethod *method)
4587 return MONO_BREAK_POLICY_ALWAYS;
4590 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4593 * mono_set_break_policy:
4594 * \param policy_callback the new callback function
4596 * Allow embedders to decide whether to actually obey breakpoint instructions
4597 * (both break IL instructions and \c Debugger.Break method calls), for example
4598 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4599 * untrusted or semi-trusted code.
4601 * \p policy_callback will be called every time a break point instruction needs to
4602 * be inserted with the method argument being the method that calls \c Debugger.Break
4603 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4604 * if it wants the breakpoint to not be effective in the given method.
4605 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4608 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4610 if (policy_callback)
4611 break_policy_func = policy_callback;
4613 break_policy_func = always_insert_breakpoint;
4617 mini_should_insert_breakpoint (MonoMethod *method)
4619 switch (break_policy_func (method)) {
4620 case MONO_BREAK_POLICY_ALWAYS:
4622 case MONO_BREAK_POLICY_NEVER:
4624 case MONO_BREAK_POLICY_ON_DBG:
4625 g_warning ("mdb no longer supported");
4628 g_warning ("Incorrect value returned from break policy callback");
4633 // Custom handlers currently only implemented by Windows.
4636 mono_runtime_install_custom_handlers (const char *handlers)
4642 mono_runtime_install_custom_handlers_usage (void)
4645 "Custom Handlers:\n"
4646 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4647 " separated list of available handlers to install.\n"
4649 "No handlers supported on current platform.\n");
4651 #endif /* HOST_WIN32 */