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);
2436 if (debug_options.dyn_runtime_invoke)
2437 g_assert (info->dyn_call_info);
2442 ret_type = sig->ret;
2443 switch (ret_type->type) {
2444 case MONO_TYPE_VOID:
2456 case MONO_TYPE_BOOLEAN:
2457 case MONO_TYPE_CHAR:
2460 info->ret_box_class = mono_class_from_mono_type (ret_type);
2463 info->ret_box_class = mono_defaults.int_class;
2465 case MONO_TYPE_STRING:
2466 case MONO_TYPE_CLASS:
2467 case MONO_TYPE_ARRAY:
2468 case MONO_TYPE_SZARRAY:
2469 case MONO_TYPE_OBJECT:
2471 case MONO_TYPE_GENERICINST:
2472 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2473 info->ret_box_class = mono_class_from_mono_type (ret_type);
2475 case MONO_TYPE_VALUETYPE:
2476 info->ret_box_class = mono_class_from_mono_type (ret_type);
2479 g_assert_not_reached ();
2483 if (!info->dyn_call_info) {
2484 if (mono_llvm_only) {
2485 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2486 g_assert_not_reached ();
2488 info->gsharedvt_invoke = TRUE;
2489 if (!callee_gsharedvt) {
2490 /* Invoke a gsharedvt out wrapper instead */
2491 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2492 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2494 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2495 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2497 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2498 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2499 g_free (wrapper_sig);
2501 info->compiled_method = mono_jit_compile_method (wrapper, error);
2502 if (!mono_error_ok (error)) {
2507 /* Gsharedvt methods can be invoked the same way */
2508 /* The out wrapper has the same signature as the compiled gsharedvt method */
2509 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2511 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2513 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2514 g_free (wrapper_sig);
2517 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2518 if (!mono_error_ok (error)) {
2528 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2530 MonoMethodSignature *sig = info->sig;
2531 MonoDomain *domain = mono_domain_get ();
2532 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2534 gpointer retval_ptr;
2535 guint8 retval [256];
2536 gpointer *param_refs;
2541 g_assert (info->gsharedvt_invoke);
2544 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2545 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2546 * signatures, so we only have to generate runtime invoke wrappers for these
2548 * This code also handles invocation of gsharedvt methods directly, no
2549 * out wrappers are used in that case.
2551 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2552 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2555 * The runtime invoke wrappers expects pointers to primitive types, so have to
2559 args [pindex ++] = &obj;
2560 if (sig->ret->type != MONO_TYPE_VOID) {
2561 retval_ptr = (gpointer)&retval;
2562 args [pindex ++] = &retval_ptr;
2564 for (i = 0; i < sig->param_count; ++i) {
2565 MonoType *t = sig->params [i];
2567 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2568 MonoClass *klass = mono_class_from_mono_type (t);
2569 guint8 *nullable_buf;
2572 size = mono_class_value_size (klass, NULL);
2573 nullable_buf = g_alloca (size);
2574 g_assert (nullable_buf);
2576 /* The argument pointed to by params [i] is either a boxed vtype or null */
2577 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2578 params [i] = nullable_buf;
2581 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2582 param_refs [i] = params [i];
2583 params [i] = &(param_refs [i]);
2585 args [pindex ++] = ¶ms [i];
2587 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2588 args [pindex ++] = &info->wrapper_arg;
2590 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2592 runtime_invoke (NULL, args, exc, info->compiled_method);
2596 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2597 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2599 return *(MonoObject**)retval;
2603 * mono_jit_runtime_invoke:
2604 * \param method: the method to invoke
2605 * \param obj: this pointer
2606 * \param params: array of parameter values.
2607 * \param exc: Set to the exception raised in the managed method.
2608 * \param error: error or caught exception object
2609 * If \p exc is NULL, \p error is thrown instead.
2610 * If coop is enabled, \p exc argument is ignored -
2611 * all exceptions are caught and propagated through \p error
2614 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2616 MonoMethod *invoke, *callee;
2617 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2618 MonoDomain *domain = mono_domain_get ();
2619 MonoJitDomainInfo *domain_info;
2620 RuntimeInvokeInfo *info, *info2;
2621 MonoJitInfo *ji = NULL;
2622 gboolean callee_gsharedvt = FALSE;
2624 #ifdef ENABLE_INTERPRETER
2625 if (mono_use_interpreter)
2626 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2633 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2634 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2638 domain_info = domain_jit_info (domain);
2640 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2643 if (mono_security_core_clr_enabled ()) {
2645 * This might be redundant since mono_class_vtable () already does this,
2646 * but keep it just in case for moonlight.
2648 mono_class_setup_vtable (method->klass);
2649 if (mono_class_has_failure (method->klass)) {
2650 mono_error_set_for_class_failure (error, method->klass);
2652 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2657 gpointer compiled_method;
2660 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2661 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2663 * Array Get/Set/Address methods. The JIT implements them using inline code
2664 * inside the runtime invoke wrappers, so no need to compile them.
2666 if (mono_aot_only) {
2668 * Call a wrapper, since the runtime invoke wrapper was not generated.
2670 MonoMethod *wrapper;
2672 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2673 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2681 compiled_method = mono_jit_compile_method (callee, error);
2682 if (!compiled_method) {
2683 g_assert (!mono_error_ok (error));
2687 if (mono_llvm_only) {
2688 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2689 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2690 if (callee_gsharedvt)
2691 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2694 if (!callee_gsharedvt)
2695 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2697 compiled_method = NULL;
2700 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2701 if (!mono_error_ok (error))
2704 mono_domain_lock (domain);
2705 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2706 mono_domain_unlock (domain);
2714 * We need this here because mono_marshal_get_runtime_invoke can place
2715 * the helper method in System.Object and not the target class.
2717 if (!mono_runtime_class_init_full (info->vtable, error)) {
2719 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2723 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2724 we always catch the exception and propagate it through the MonoError */
2725 gboolean catchExcInMonoError =
2726 (exc == NULL) && mono_threads_is_coop_enabled ();
2727 MonoObject *invoke_exc = NULL;
2728 if (catchExcInMonoError)
2731 /* The wrappers expect this to be initialized to NULL */
2735 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2736 if (info->dyn_call_info) {
2737 MonoMethodSignature *sig = mono_method_signature (method);
2739 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2740 int i, pindex, buf_size;
2742 guint8 retval [256];
2744 if (!dyn_runtime_invoke) {
2745 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2746 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2747 if (!mono_error_ok (error))
2751 /* Convert the arguments to the format expected by start_dyn_call () */
2752 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2755 args [pindex ++] = &obj;
2756 for (i = 0; i < sig->param_count; ++i) {
2757 MonoType *t = sig->params [i];
2760 args [pindex ++] = ¶ms [i];
2761 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2762 args [pindex ++] = ¶ms [i];
2764 args [pindex ++] = params [i];
2768 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2770 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
2771 buf = g_alloca (buf_size);
2774 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
2776 dyn_runtime_invoke (buf, exc, info->compiled_method);
2777 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2779 if (catchExcInMonoError && *exc != NULL) {
2780 mono_error_set_exception_instance (error, (MonoException*) *exc);
2784 if (info->ret_box_class)
2785 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2787 return *(MonoObject**)retval;
2793 if (mono_llvm_only) {
2794 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2798 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2800 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2802 if (catchExcInMonoError && *exc != NULL)
2803 mono_error_set_exception_instance (error, (MonoException*) *exc);
2812 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2815 * mini_llvmonly_initial_imt_tramp:
2817 * This function is called the first time a call is made through an IMT trampoline.
2818 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2821 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2823 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2828 mono_vtable_build_imt_slot (info->vtable, info->slot);
2830 imt = (gpointer*)info->vtable;
2831 imt -= MONO_IMT_SIZE;
2833 /* Return what the real IMT trampoline returns */
2834 ftndesc = imt [info->slot];
2837 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2838 /* Happens when the imt slot contains only a generic virtual method */
2840 return func ((gpointer *)ftndesc [1], imt_method);
2843 /* This is called indirectly through an imt slot. */
2845 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2849 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2850 while (arg [i] && arg [i] != imt_method)
2857 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2859 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2861 //g_assert (arg [0] == imt_method);
2866 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2868 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2869 if (arg [0] == imt_method)
2876 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2878 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2879 if (arg [0] == imt_method)
2881 else if (arg [2] == imt_method)
2888 * A version of the imt trampoline used for generic virtual/variant iface methods.
2889 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2890 * in the search table. The original JIT code had a 'fallback' trampoline it could
2891 * call, but we can't do that, so we just return NULL, and the compiled code
2895 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2899 while (arg [i] && arg [i] != imt_method)
2908 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2912 int i, index, real_count;
2913 gboolean virtual_generic = FALSE;
2916 * Create an array which is passed to the imt trampoline functions.
2917 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2921 for (i = 0; i < count; ++i) {
2922 MonoIMTCheckItem *item = imt_entries [i];
2924 if (item->is_equals)
2926 if (item->has_target_code)
2927 virtual_generic = TRUE;
2931 * Initialize all vtable entries reachable from this imt slot, so the compiled
2932 * code doesn't have to check it.
2934 for (i = 0; i < count; ++i) {
2935 MonoIMTCheckItem *item = imt_entries [i];
2938 if (!item->is_equals || item->has_target_code)
2940 vt_slot = item->value.vtable_slot;
2941 mono_init_vtable_slot (vtable, vt_slot);
2944 /* Save the entries into an array */
2945 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2947 for (i = 0; i < count; ++i) {
2948 MonoIMTCheckItem *item = imt_entries [i];
2950 if (!item->is_equals)
2953 g_assert (item->key);
2954 buf [(index * 2)] = item->key;
2955 if (item->has_target_code)
2956 buf [(index * 2) + 1] = item->value.target_code;
2958 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2961 buf [(index * 2)] = NULL;
2962 buf [(index * 2) + 1] = fail_tramp;
2965 * Return a function descriptor for a C function with 'buf' as its argument.
2966 * It will by called by JITted code.
2968 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2969 switch (real_count) {
2971 res [0] = mono_llvmonly_imt_tramp_1;
2974 res [0] = mono_llvmonly_imt_tramp_2;
2977 res [0] = mono_llvmonly_imt_tramp_3;
2980 res [0] = mono_llvmonly_imt_tramp;
2983 if (virtual_generic || fail_tramp)
2984 res [0] = mono_llvmonly_fallback_imt_tramp;
2990 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2992 MonoException *exc = NULL;
2994 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2995 MONO_SIG_HANDLER_GET_CONTEXT;
2997 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2999 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3001 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3002 if (mono_arch_is_int_overflow (ctx, info))
3004 * The spec says this throws ArithmeticException, but MS throws the derived
3005 * OverflowException.
3007 exc = mono_get_exception_overflow ();
3009 exc = mono_get_exception_divide_by_zero ();
3011 exc = mono_get_exception_divide_by_zero ();
3015 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3018 mono_handle_native_crash ("SIGFPE", ctx, info);
3019 if (mono_do_crash_chaining) {
3020 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3025 mono_arch_handle_exception (ctx, exc);
3028 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3031 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3033 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3034 MONO_SIG_HANDLER_GET_CONTEXT;
3036 if (mono_runtime_get_no_exec ())
3040 mono_handle_native_crash ("SIGILL", ctx, info);
3041 if (mono_do_crash_chaining) {
3042 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3046 g_assert_not_reached ();
3049 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3050 #define HAVE_SIG_INFO
3053 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3056 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3057 gpointer fault_addr = NULL;
3058 #ifdef HAVE_SIG_INFO
3059 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3063 MONO_SIG_HANDLER_GET_CONTEXT;
3065 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3066 if (mono_arch_is_single_step_event (info, ctx)) {
3067 mono_debugger_agent_single_step_event (ctx);
3069 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3070 mono_debugger_agent_breakpoint_hit (ctx);
3075 #if defined(HAVE_SIG_INFO)
3076 #if !defined(HOST_WIN32)
3077 fault_addr = info->si_addr;
3078 if (mono_aot_is_pagefault (info->si_addr)) {
3079 mono_aot_handle_pagefault (info->si_addr);
3084 /* The thread might no be registered with the runtime */
3085 if (!mono_domain_get () || !jit_tls) {
3086 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3088 mono_handle_native_crash ("SIGSEGV", ctx, info);
3089 if (mono_do_crash_chaining) {
3090 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3096 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3098 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3099 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3102 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3103 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3104 fault_addr = info->si_addr;
3105 if (fault_addr == NULL) {
3108 mono_sigctx_to_monoctx (ctx, &mctx);
3110 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3114 if (jit_tls->stack_size &&
3115 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3117 * The hard-guard page has been hit: there is not much we can do anymore
3118 * Print a hopefully clear message and abort.
3120 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3121 g_assert_not_reached ();
3123 /* The original handler might not like that it is executed on an altstack... */
3124 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3127 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3132 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3135 mono_handle_native_crash ("SIGSEGV", ctx, info);
3137 if (mono_do_crash_chaining) {
3138 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3143 mono_arch_handle_exception (ctx, NULL);
3147 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3150 MONO_SIG_HANDLER_GET_CONTEXT;
3152 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3154 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3156 mono_arch_handle_exception (ctx, exc);
3158 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3161 #ifndef DISABLE_REMOTING
3162 /* mono_jit_create_remoting_trampoline:
3163 * @method: pointer to the method info
3165 * Creates a trampoline which calls the remoting functions. This
3166 * is used in the vtable of transparent proxies.
3168 * Returns: a pointer to the newly created code
3171 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3174 guint8 *addr = NULL;
3178 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3179 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3183 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3184 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3185 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3188 addr = (guint8 *)mono_compile_method_checked (nm, error);
3189 return_val_if_nok (error, NULL);
3190 return mono_get_addr_from_ftnptr (addr);
3194 static G_GNUC_UNUSED void
3195 no_imt_trampoline (void)
3197 g_assert_not_reached ();
3200 static G_GNUC_UNUSED void
3201 no_vcall_trampoline (void)
3203 g_assert_not_reached ();
3206 static gpointer *vtable_trampolines;
3207 static int vtable_trampolines_size;
3210 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3212 int index = slot_index + MONO_IMT_SIZE;
3214 if (mono_llvm_only) {
3215 if (slot_index < 0) {
3216 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3217 // FIXME: Memory management
3218 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3219 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3222 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3224 mono_memory_barrier ();
3231 g_assert (slot_index >= - MONO_IMT_SIZE);
3232 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3234 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3238 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3239 while (new_size <= index)
3241 new_table = g_new0 (gpointer, new_size);
3243 if (vtable_trampolines)
3244 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3245 g_free (vtable_trampolines);
3246 mono_memory_barrier ();
3247 vtable_trampolines = (void **)new_table;
3248 vtable_trampolines_size = new_size;
3253 if (!vtable_trampolines [index])
3254 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3255 return vtable_trampolines [index];
3259 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3261 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3265 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3270 gpointer *imt = (gpointer*)vt;
3271 imt -= MONO_IMT_SIZE;
3273 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3277 is_callee_gsharedvt_variable (gpointer addr)
3280 gboolean callee_gsharedvt;
3282 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3284 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3285 if (callee_gsharedvt)
3286 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3287 return callee_gsharedvt;
3291 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3293 gpointer arg = NULL;
3295 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3296 arg = mini_method_get_rgctx (method);
3299 * Avoid adding gsharedvt in wrappers since they might not exist if
3300 * this delegate is called through a gsharedvt delegate invoke wrapper.
3301 * Instead, encode that the method is gsharedvt in del->extra_arg,
3302 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3304 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3305 g_assert ((((mgreg_t)arg) & 1) == 0);
3306 arg = (gpointer)(((mgreg_t)arg) | 1);
3312 mini_init_delegate (MonoDelegate *del)
3315 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3316 #ifdef ENABLE_INTERPRETER
3317 if (mono_use_interpreter)
3318 mono_interp_init_delegate (del);
3323 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3327 abs_offset = offset;
3329 abs_offset = - abs_offset;
3330 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3334 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3336 gboolean is_virtual_generic, is_interface, load_imt_reg;
3339 static guint8 **cache = NULL;
3340 static int cache_size = 0;
3345 if (MONO_TYPE_ISSTRUCT (sig->ret))
3348 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3349 is_interface = mono_class_is_interface (method->klass);
3350 load_imt_reg = is_virtual_generic || is_interface;
3353 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3355 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3357 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3358 g_assert (idx >= 0);
3360 /* Resize the cache to idx + 1 */
3361 if (cache_size < idx + 1) {
3363 if (cache_size < idx + 1) {
3365 int new_cache_size = idx + 1;
3367 new_cache = g_new0 (guint8*, new_cache_size);
3369 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3372 mono_memory_barrier ();
3374 cache_size = new_cache_size;
3382 /* FIXME Support more cases */
3383 if (mono_aot_only) {
3384 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3385 g_assert (cache [idx]);
3387 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3393 * mini_parse_debug_option:
3394 * @option: The option to parse.
3396 * Parses debug options for the mono runtime. The options are the same as for
3397 * the MONO_DEBUG environment variable.
3401 mini_parse_debug_option (const char *option)
3403 if (!strcmp (option, "handle-sigint"))
3404 debug_options.handle_sigint = TRUE;
3405 else if (!strcmp (option, "keep-delegates"))
3406 debug_options.keep_delegates = TRUE;
3407 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3408 debug_options.reverse_pinvoke_exceptions = TRUE;
3409 else if (!strcmp (option, "collect-pagefault-stats"))
3410 debug_options.collect_pagefault_stats = TRUE;
3411 else if (!strcmp (option, "break-on-unverified"))
3412 debug_options.break_on_unverified = TRUE;
3413 else if (!strcmp (option, "no-gdb-backtrace"))
3414 debug_options.no_gdb_backtrace = TRUE;
3415 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3416 debug_options.suspend_on_native_crash = TRUE;
3417 else if (!strcmp (option, "suspend-on-exception"))
3418 debug_options.suspend_on_exception = TRUE;
3419 else if (!strcmp (option, "suspend-on-unhandled"))
3420 debug_options.suspend_on_unhandled = TRUE;
3421 else if (!strcmp (option, "dont-free-domains"))
3422 mono_dont_free_domains = TRUE;
3423 else if (!strcmp (option, "dyn-runtime-invoke"))
3424 debug_options.dyn_runtime_invoke = TRUE;
3425 else if (!strcmp (option, "gdb"))
3426 debug_options.gdb = TRUE;
3427 else if (!strcmp (option, "lldb"))
3428 debug_options.lldb = TRUE;
3429 else if (!strcmp (option, "explicit-null-checks"))
3430 debug_options.explicit_null_checks = TRUE;
3431 else if (!strcmp (option, "gen-seq-points"))
3432 debug_options.gen_sdb_seq_points = TRUE;
3433 else if (!strcmp (option, "gen-compact-seq-points"))
3434 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3435 else if (!strcmp (option, "no-compact-seq-points"))
3436 debug_options.no_seq_points_compact_data = TRUE;
3437 else if (!strcmp (option, "single-imm-size"))
3438 debug_options.single_imm_size = TRUE;
3439 else if (!strcmp (option, "init-stacks"))
3440 debug_options.init_stacks = TRUE;
3441 else if (!strcmp (option, "casts"))
3442 debug_options.better_cast_details = TRUE;
3443 else if (!strcmp (option, "soft-breakpoints"))
3444 debug_options.soft_breakpoints = TRUE;
3445 else if (!strcmp (option, "check-pinvoke-callconv"))
3446 debug_options.check_pinvoke_callconv = TRUE;
3447 else if (!strcmp (option, "use-fallback-tls"))
3448 debug_options.use_fallback_tls = TRUE;
3449 else if (!strcmp (option, "debug-domain-unload"))
3450 mono_enable_debug_domain_unload (TRUE);
3451 else if (!strcmp (option, "partial-sharing"))
3452 mono_set_partial_sharing_supported (TRUE);
3453 else if (!strcmp (option, "align-small-structs"))
3454 mono_align_small_structs = TRUE;
3455 else if (!strcmp (option, "native-debugger-break"))
3456 debug_options.native_debugger_break = TRUE;
3457 else if (!strcmp (option, "disable_omit_fp"))
3458 debug_options.disable_omit_fp = TRUE;
3466 mini_parse_debug_options (void)
3468 char *options = g_getenv ("MONO_DEBUG");
3469 gchar **args, **ptr;
3474 args = g_strsplit (options, ",", -1);
3477 for (ptr = args; ptr && *ptr; ptr++) {
3478 const char *arg = *ptr;
3480 if (!mini_parse_debug_option (arg)) {
3481 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3482 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");
3491 mini_get_debug_options (void)
3493 return &debug_options;
3497 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3499 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3502 gpointer* desc = NULL;
3504 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3506 # if defined(__ppc64__) || defined(__powerpc64__)
3508 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3514 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3520 mini_get_addr_from_ftnptr (gpointer descr)
3522 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3523 return *(gpointer*)descr;
3530 register_jit_stats (void)
3532 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3533 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3534 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3535 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3536 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3537 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3538 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);
3539 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3540 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3541 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3542 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3543 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3544 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3545 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3546 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3547 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3548 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3549 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3550 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3551 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3552 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3553 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3554 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3555 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3556 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3557 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3558 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3559 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3560 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3561 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3562 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3563 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3564 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3565 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3566 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3567 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3568 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3569 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3570 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3571 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3572 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3573 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3574 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3575 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3576 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3577 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3578 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3579 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3580 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3581 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3582 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3583 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3584 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3585 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3586 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3587 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3588 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3589 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3590 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3591 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3592 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3595 static void runtime_invoke_info_free (gpointer value);
3598 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3600 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3601 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3603 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3607 class_method_pair_hash (gconstpointer data)
3609 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3611 return (gsize)pair->klass ^ (gsize)pair->method;
3615 mini_create_jit_domain_info (MonoDomain *domain)
3617 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3619 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3620 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3621 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3622 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3623 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3624 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3625 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3626 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3627 mono_jit_code_hash_init (&info->interp_code_hash);
3629 domain->runtime_info = info;
3633 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3635 MonoJumpList *jlist = (MonoJumpList *)value;
3636 g_slist_free (jlist->list);
3640 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3642 GSList *list = (GSList *)value;
3643 g_slist_free (list);
3647 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3649 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3650 mono_code_manager_destroy (di->code_mp);
3655 runtime_invoke_info_free (gpointer value)
3657 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3659 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3660 if (info->dyn_call_info)
3661 mono_arch_dyn_call_free (info->dyn_call_info);
3667 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3669 g_slist_free (value);
3673 mini_free_jit_domain_info (MonoDomain *domain)
3675 MonoJitDomainInfo *info = domain_jit_info (domain);
3677 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3678 g_hash_table_destroy (info->jump_target_hash);
3679 if (info->jump_target_got_slot_hash) {
3680 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3681 g_hash_table_destroy (info->jump_target_got_slot_hash);
3683 if (info->dynamic_code_hash) {
3684 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3685 g_hash_table_destroy (info->dynamic_code_hash);
3687 if (info->method_code_hash)
3688 g_hash_table_destroy (info->method_code_hash);
3689 g_hash_table_destroy (info->jump_trampoline_hash);
3690 g_hash_table_destroy (info->jit_trampoline_hash);
3691 g_hash_table_destroy (info->delegate_trampoline_hash);
3692 if (info->static_rgctx_trampoline_hash)
3693 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3694 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3695 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3696 g_hash_table_destroy (info->seq_points);
3697 g_hash_table_destroy (info->arch_seq_points);
3698 if (info->agent_info)
3699 mono_debugger_agent_free_domain_info (domain);
3700 if (info->gsharedvt_arg_tramp_hash)
3701 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3702 if (info->llvm_jit_callees) {
3703 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3704 g_hash_table_destroy (info->llvm_jit_callees);
3706 mono_internal_hash_table_destroy (&info->interp_code_hash);
3708 mono_llvm_free_domain_info (domain);
3711 g_free (domain->runtime_info);
3712 domain->runtime_info = NULL;
3715 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3718 code_manager_chunk_new (void *chunk, int size)
3720 mono_arch_code_chunk_new (chunk, size);
3724 code_manager_chunk_destroy (void *chunk)
3726 mono_arch_code_chunk_destroy (chunk);
3733 llvm_init_inner (void)
3735 if (!mono_llvm_load (NULL))
3746 * Load and initialize LLVM support.
3747 * Return TRUE on success.
3750 mini_llvm_init (void)
3753 static gboolean llvm_inited;
3754 static gboolean init_result;
3756 mono_loader_lock_if_inited ();
3758 init_result = llvm_init_inner ();
3761 mono_loader_unlock_if_inited ();
3769 mini_add_profiler_argument (const char *desc)
3771 if (!profile_options)
3772 profile_options = g_ptr_array_new ();
3774 g_ptr_array_add (profile_options, (gpointer) desc);
3778 mini_init (const char *filename, const char *runtime_version)
3782 MonoRuntimeCallbacks callbacks;
3783 MonoThreadInfoRuntimeCallbacks ticallbacks;
3784 MonoCodeManagerCallbacks code_manager_callbacks;
3786 MONO_VES_INIT_BEGIN ();
3788 CHECKED_MONO_INIT ();
3790 #if defined(__linux__)
3791 if (access ("/proc/self/maps", F_OK) != 0) {
3792 g_print ("Mono requires /proc to be mounted.\n");
3797 #ifdef ENABLE_INTERPRETER
3798 mono_interp_init ();
3801 mono_os_mutex_init_recursive (&jit_mutex);
3803 mono_cross_helpers_run ();
3805 mono_counters_init ();
3809 mini_jit_init_job_control ();
3811 /* Happens when using the embedding interface */
3812 if (!default_opt_set)
3813 default_opt = mono_parse_default_optimizations (NULL);
3815 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3817 mono_set_generic_sharing_vt_supported (TRUE);
3820 mono_set_generic_sharing_vt_supported (TRUE);
3823 mono_tls_init_runtime_keys ();
3825 if (!global_codeman)
3826 global_codeman = mono_code_manager_new ();
3828 memset (&callbacks, 0, sizeof (callbacks));
3829 callbacks.create_ftnptr = mini_create_ftnptr;
3830 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3831 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3832 callbacks.set_cast_details = mono_set_cast_details;
3833 callbacks.debug_log = mono_debugger_agent_debug_log;
3834 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3835 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3836 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3837 callbacks.imt_entry_inited = mini_imt_entry_inited;
3838 callbacks.init_delegate = mini_init_delegate;
3839 #define JIT_INVOKE_WORKS
3840 #ifdef JIT_INVOKE_WORKS
3841 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3843 #define JIT_TRAMPOLINES_WORK
3844 #ifdef JIT_TRAMPOLINES_WORK
3845 callbacks.compile_method = mono_jit_compile_method;
3846 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3847 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3848 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3849 callbacks.free_method = mono_jit_free_method;
3850 #ifndef DISABLE_REMOTING
3851 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3855 mono_install_callbacks (&callbacks);
3857 memset (&ticallbacks, 0, sizeof (ticallbacks));
3858 ticallbacks.setup_async_callback = mono_setup_async_callback;
3859 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3860 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3861 ticallbacks.thread_state_init = mono_thread_state_init;
3864 mono_w32handle_init ();
3867 mono_thread_info_runtime_init (&ticallbacks);
3869 if (g_hasenv ("MONO_DEBUG")) {
3870 mini_parse_debug_options ();
3873 mono_code_manager_init ();
3875 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3876 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3877 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3878 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3880 mono_code_manager_install_callbacks (&code_manager_callbacks);
3884 mono_arch_cpu_init ();
3888 mono_unwind_init ();
3890 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3891 mono_lldb_init ("");
3892 mono_dont_free_domains = TRUE;
3895 #ifdef XDEBUG_ENABLED
3896 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3898 mono_xdebug_init (mono_xdebug);
3899 g_free (mono_xdebug);
3900 /* So methods for multiple domains don't have the same address */
3901 mono_dont_free_domains = TRUE;
3902 mono_using_xdebug = TRUE;
3903 } else if (mini_get_debug_options ()->gdb) {
3904 mono_xdebug_init ((char*)"gdb");
3905 mono_dont_free_domains = TRUE;
3906 mono_using_xdebug = TRUE;
3911 if (mono_use_llvm) {
3912 if (!mono_llvm_load (NULL)) {
3913 mono_use_llvm = FALSE;
3914 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3921 mono_trampolines_init ();
3923 if (default_opt & MONO_OPT_AOT)
3926 mono_debugger_agent_init ();
3928 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3929 mono_set_generic_sharing_supported (TRUE);
3932 mono_thread_info_signals_init ();
3934 #ifndef MONO_CROSS_COMPILE
3935 mono_runtime_install_handlers ();
3937 mono_threads_install_cleanup (mini_thread_cleanup);
3939 #ifdef JIT_TRAMPOLINES_WORK
3940 mono_install_create_domain_hook (mini_create_jit_domain_info);
3941 mono_install_free_domain_hook (mini_free_jit_domain_info);
3943 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3944 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3945 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3947 mono_profiler_state.context_enable = mini_profiler_context_enable;
3948 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
3949 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
3950 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
3951 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
3952 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
3954 if (profile_options)
3955 for (guint i = 0; i < profile_options->len; i++)
3956 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
3958 mono_profiler_started ();
3960 if (debug_options.collect_pagefault_stats)
3961 mono_aot_set_make_unreadable (TRUE);
3963 if (runtime_version)
3964 domain = mono_init_version (filename, runtime_version);
3966 domain = mono_init_from_assembly (filename, filename);
3968 if (mono_aot_only) {
3969 /* This helps catch code allocation requests */
3970 mono_code_manager_set_read_only (domain->code_mp);
3971 mono_marshal_use_aot_wrappers (TRUE);
3974 if (mono_llvm_only) {
3975 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3976 mono_set_always_build_imt_trampolines (TRUE);
3977 } else if (mono_aot_only) {
3978 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3980 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3983 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3984 mono_arch_finish_init ();
3988 /* This must come after mono_init () in the aot-only case */
3989 mono_exceptions_init ();
3991 /* This should come after mono_init () too */
3995 mono_create_helper_signatures ();
3998 register_jit_stats ();
4000 #define JIT_CALLS_WORK
4001 #ifdef JIT_CALLS_WORK
4002 /* Needs to be called here since register_jit_icall depends on it */
4003 mono_marshal_init ();
4005 mono_arch_register_lowlevel_calls ();
4009 mono_generic_sharing_init ();
4012 #ifdef MONO_ARCH_SIMD_INTRINSICS
4013 mono_simd_intrinsics_init ();
4016 mono_tasklets_init ();
4018 register_trampolines (domain);
4020 if (mono_compile_aot)
4022 * Avoid running managed code when AOT compiling, since the platform
4023 * might only support aot-only execution.
4025 mono_runtime_set_no_exec (TRUE);
4027 mono_mem_account_register_counters ();
4029 #define JIT_RUNTIME_WORKS
4030 #ifdef JIT_RUNTIME_WORKS
4031 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4032 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4033 mono_error_assert_ok (&error);
4034 mono_thread_attach (domain);
4035 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4038 if (mono_profiler_sampling_enabled ())
4039 mono_runtime_setup_stat_profiler ();
4041 MONO_PROFILER_RAISE (runtime_initialized, ());
4043 MONO_VES_INIT_END ();
4049 register_icalls (void)
4051 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4052 ves_icall_get_frame_info);
4053 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4054 ves_icall_get_trace);
4055 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4056 mono_runtime_install_handlers);
4057 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4058 mono_runtime_cleanup_handlers);
4060 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4061 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4062 mono_debugger_agent_unhandled_exception);
4066 * It's important that we pass `TRUE` as the last argument here, as
4067 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4068 * *did* emit a wrapper, we'd be looking at infinite recursion since
4069 * the wrapper would call the icall which would call the wrapper and
4072 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4073 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4074 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4076 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4077 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4078 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4079 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4080 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4081 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4083 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4084 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4085 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4086 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4087 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4088 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4089 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4090 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4091 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4093 // FIXME: This is broken
4094 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4097 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4098 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4099 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4100 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4101 register_icall (mono_thread_self_abort, "mono_thread_self_abort", "void", FALSE);
4102 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4103 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4105 if (mono_threads_is_coop_enabled ())
4106 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4108 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4109 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4110 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4111 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4112 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4113 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4115 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4116 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4117 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4120 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4121 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4122 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4123 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4126 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4127 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4128 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4129 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4130 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4133 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4134 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4137 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4138 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4139 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4142 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4143 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4146 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4147 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4148 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4149 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4150 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4151 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4152 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4155 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4156 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4157 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4160 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4161 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);
4163 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4164 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4166 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4167 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4169 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4170 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);
4172 #ifdef MONO_ARCH_EMULATE_FREM
4173 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4174 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4177 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4178 if (mono_arch_is_soft_float ()) {
4179 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4180 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4181 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4182 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4183 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4184 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4185 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4186 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4187 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4188 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4189 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4190 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4192 #if SIZEOF_VOID_P == 4
4193 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4196 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4197 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4198 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4199 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4200 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4201 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4202 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4203 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4204 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4205 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4207 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4208 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4209 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4210 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4211 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4213 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4214 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4215 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4216 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4219 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4221 #ifdef COMPRESSED_INTERFACE_BITMAP
4222 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4225 #if SIZEOF_REGISTER == 4
4226 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4228 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4231 /* other jit icalls */
4232 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4233 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4234 "ptr ptr ptr", FALSE);
4235 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4236 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4237 "ptr ptr ptr ptr", FALSE);
4238 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4239 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4240 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4241 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4242 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4243 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4244 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4245 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4246 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4247 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4248 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4249 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4250 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4251 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4252 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4253 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4254 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4255 register_icall (mono_break, "mono_break", NULL, TRUE);
4256 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4257 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4258 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4259 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4260 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4261 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4262 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4263 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4264 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4265 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4266 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4268 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4269 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4271 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4272 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4273 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4274 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4275 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4277 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4279 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4280 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4281 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4282 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4284 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4285 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4286 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4287 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4288 /* This needs a wrapper so it can have a preserveall cconv */
4289 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4290 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4291 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4292 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4293 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4294 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4295 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4297 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4298 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4299 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4300 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4303 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4305 /* Register tls icalls */
4306 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4307 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4308 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4309 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4310 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4311 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4312 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4313 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4314 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4315 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4318 MonoJitStats mono_jit_stats = {0};
4321 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4322 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4324 MONO_NO_SANITIZE_THREAD
4326 print_jit_stats (void)
4328 if (mono_jit_stats.enabled) {
4329 g_print ("Mono Jit statistics\n");
4330 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4331 mono_jit_stats.max_ratio_method);
4332 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4333 mono_jit_stats.biggest_method);
4335 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4336 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4337 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4338 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4339 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4340 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4341 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4342 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4344 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4345 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4346 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4348 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4349 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4350 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4351 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4353 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4354 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4355 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4356 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4357 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4358 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4359 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4360 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4362 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4363 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4364 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4366 g_free (mono_jit_stats.max_ratio_method);
4367 mono_jit_stats.max_ratio_method = NULL;
4368 g_free (mono_jit_stats.biggest_method);
4369 mono_jit_stats.biggest_method = NULL;
4374 mini_cleanup (MonoDomain *domain)
4376 if (mono_profiler_sampling_enabled ())
4377 mono_runtime_shutdown_stat_profiler ();
4379 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4382 cominterop_release_all_rcws ();
4385 #ifndef MONO_CROSS_COMPILE
4387 * mono_domain_finalize () needs to be called early since it needs the
4388 * execution engine still fully working (it may invoke managed finalizers).
4390 mono_domain_finalize (domain, 2000);
4393 /* This accesses metadata so needs to be called before runtime shutdown */
4396 #ifndef MONO_CROSS_COMPILE
4397 mono_runtime_cleanup (domain);
4400 mono_threadpool_cleanup ();
4402 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4404 mono_profiler_cleanup ();
4406 if (profile_options)
4407 g_ptr_array_free (profile_options, TRUE);
4409 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4411 mono_icall_cleanup ();
4413 mono_runtime_cleanup_handlers ();
4415 #ifndef MONO_CROSS_COMPILE
4416 mono_domain_free (domain, TRUE);
4421 mono_llvm_cleanup ();
4424 mono_aot_cleanup ();
4426 mono_trampolines_cleanup ();
4428 mono_unwind_cleanup ();
4430 mono_code_manager_destroy (global_codeman);
4431 g_free (vtable_trampolines);
4433 mini_jit_cleanup ();
4435 mono_tramp_info_cleanup ();
4437 mono_arch_cleanup ();
4439 mono_generic_sharing_cleanup ();
4443 mono_trace_cleanup ();
4445 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4447 if (mono_inject_async_exc_method)
4448 mono_method_desc_free (mono_inject_async_exc_method);
4450 mono_tls_free_keys ();
4452 mono_os_mutex_destroy (&jit_mutex);
4454 mono_code_manager_cleanup ();
4457 mono_w32handle_cleanup ();
4462 mono_set_defaults (int verbose_level, guint32 opts)
4464 mini_verbose = verbose_level;
4465 mono_set_optimizations (opts);
4469 mono_disable_optimizations (guint32 opts)
4471 default_opt &= ~opts;
4475 mono_set_optimizations (guint32 opts)
4478 default_opt_set = TRUE;
4479 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4480 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4483 mono_set_generic_sharing_vt_supported (TRUE);
4488 mono_set_verbose_level (guint32 level)
4490 mini_verbose = level;
4494 * mono_get_runtime_build_info:
4495 * The returned string is owned by the caller. The returned string
4496 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4497 * \returns the runtime version + build date in string format.
4500 mono_get_runtime_build_info (void)
4502 if (mono_build_date)
4503 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4505 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4509 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4511 GHashTable *assemblies = (GHashTable*)user_data;
4512 MonoImage *image = mono_assembly_get_image (ass);
4513 MonoMethod *method, *invoke;
4516 if (g_hash_table_lookup (assemblies, ass))
4519 g_hash_table_insert (assemblies, ass, ass);
4521 if (mini_verbose > 0)
4522 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4524 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4527 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4529 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4532 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4534 if (method->is_generic || mono_class_is_gtd (method->klass))
4538 if (mini_verbose > 1) {
4539 char * desc = mono_method_full_name (method, TRUE);
4540 g_print ("Compiling %d %s\n", count, desc);
4543 mono_compile_method_checked (method, &error);
4544 if (!is_ok (&error)) {
4545 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4548 if (strcmp (method->name, "Finalize") == 0) {
4549 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4550 mono_compile_method_checked (invoke, &error);
4551 mono_error_assert_ok (&error);
4553 #ifndef DISABLE_REMOTING
4554 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4555 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4556 mono_compile_method_checked (invoke, &error);
4557 mono_error_assert_ok (&error);
4562 /* Load and precompile referenced assemblies as well */
4563 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4564 mono_assembly_load_reference (image, i);
4565 if (image->references [i])
4566 mono_precompile_assembly (image->references [i], assemblies);
4570 void mono_precompile_assemblies ()
4572 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4574 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4576 g_hash_table_destroy (assemblies);
4581 * Have to export this for AOT.
4584 mono_personality (void)
4587 g_assert_not_reached ();
4591 static MonoBreakPolicy
4592 always_insert_breakpoint (MonoMethod *method)
4594 return MONO_BREAK_POLICY_ALWAYS;
4597 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4600 * mono_set_break_policy:
4601 * \param policy_callback the new callback function
4603 * Allow embedders to decide whether to actually obey breakpoint instructions
4604 * (both break IL instructions and \c Debugger.Break method calls), for example
4605 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4606 * untrusted or semi-trusted code.
4608 * \p policy_callback will be called every time a break point instruction needs to
4609 * be inserted with the method argument being the method that calls \c Debugger.Break
4610 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4611 * if it wants the breakpoint to not be effective in the given method.
4612 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4615 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4617 if (policy_callback)
4618 break_policy_func = policy_callback;
4620 break_policy_func = always_insert_breakpoint;
4624 mini_should_insert_breakpoint (MonoMethod *method)
4626 switch (break_policy_func (method)) {
4627 case MONO_BREAK_POLICY_ALWAYS:
4629 case MONO_BREAK_POLICY_NEVER:
4631 case MONO_BREAK_POLICY_ON_DBG:
4632 g_warning ("mdb no longer supported");
4635 g_warning ("Incorrect value returned from break policy callback");
4640 // Custom handlers currently only implemented by Windows.
4643 mono_runtime_install_custom_handlers (const char *handlers)
4649 mono_runtime_install_custom_handlers_usage (void)
4652 "Custom Handlers:\n"
4653 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4654 " separated list of available handlers to install.\n"
4656 "No handlers supported on current platform.\n");
4658 #endif /* HOST_WIN32 */