3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include "mono/metadata/profiler.h"
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/utils/mono-math.h>
55 #include <mono/utils/mono-compiler.h>
56 #include <mono/utils/mono-counters.h>
57 #include <mono/utils/mono-error-internals.h>
58 #include <mono/utils/mono-logger-internals.h>
59 #include <mono/utils/mono-mmap.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-tls.h>
62 #include <mono/utils/mono-hwcap.h>
63 #include <mono/utils/dtrace.h>
64 #include <mono/utils/mono-signal-handler.h>
65 #include <mono/utils/mono-threads.h>
66 #include <mono/utils/mono-threads-coop.h>
67 #include <mono/utils/checked-build.h>
68 #include <mono/utils/mono-proclib.h>
69 #include <mono/metadata/w32handle.h>
70 #include <mono/metadata/threadpool.h>
73 #include "seq-points.h"
80 #include "jit-icalls.h"
83 #include "mini-llvm.h"
84 #include "debugger-agent.h"
87 #ifdef MONO_ARCH_LLVM_SUPPORTED
89 #include "mini-llvm-cpp.h"
94 #ifdef ENABLE_INTERPRETER
95 #include "interp/interp.h"
98 static guint32 default_opt = 0;
99 static gboolean default_opt_set = FALSE;
101 gboolean mono_compile_aot = FALSE;
102 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
103 gboolean mono_aot_only = FALSE;
104 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
105 gboolean mono_llvm_only = FALSE;
106 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NONE;
108 const char *mono_build_date;
109 gboolean mono_do_signal_chaining;
110 gboolean mono_do_crash_chaining;
111 int mini_verbose = 0;
114 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
115 * it can load AOT code compiled by LLVM.
117 gboolean mono_use_llvm = FALSE;
119 gboolean mono_use_interpreter = FALSE;
121 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
122 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
123 static mono_mutex_t jit_mutex;
125 static MonoCodeManager *global_codeman;
127 MonoDebugOptions debug_options;
129 #ifdef VALGRIND_JIT_REGISTER_MAP
130 int valgrind_register;
132 GList* mono_aot_paths;
134 static gboolean mini_enable_profiler = FALSE;
135 static char* mini_profiler_options = NULL;
137 static GSList *tramp_infos;
139 static void register_icalls (void);
141 static gboolean mini_profiler_enabled (void) { return mini_enable_profiler; }
142 static const char* mini_profiler_get_options (void) { return mini_profiler_options; }
145 mono_running_on_valgrind (void)
148 if (RUNNING_ON_VALGRIND){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register = TRUE;
164 find_tramp (gpointer key, gpointer value, gpointer user_data)
166 FindTrampUserData *ud = (FindTrampUserData*)user_data;
169 ud->method = (MonoMethod*)key;
173 G_GNUC_UNUSED static char*
174 get_method_from_ip (void *ip)
180 MonoDomain *domain = mono_domain_get ();
181 MonoDebugSourceLocation *location;
182 FindTrampUserData user_data;
185 domain = mono_get_root_domain ();
187 ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
190 user_data.method = NULL;
191 mono_domain_lock (domain);
192 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
193 mono_domain_unlock (domain);
194 if (user_data.method) {
195 char *mname = mono_method_full_name (user_data.method, TRUE);
196 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
202 } else if (ji->is_trampoline) {
203 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
207 method = jinfo_get_method (ji);
208 method_name = mono_method_full_name (method, TRUE);
209 /* FIXME: unused ? */
210 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
212 res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
214 mono_debug_free_source_location (location);
215 g_free (method_name);
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
235 return get_method_from_ip (ip);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
250 mono_print_method_from_ip (void *ip)
254 MonoDebugSourceLocation *source;
255 MonoDomain *domain = mono_domain_get ();
256 MonoDomain *target_domain = mono_domain_get ();
257 FindTrampUserData user_data;
258 MonoGenericSharingContext*gsctx;
259 const char *shared_type;
262 domain = mono_get_root_domain ();
263 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
264 if (ji && ji->is_trampoline) {
265 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
273 user_data.method = NULL;
274 mono_domain_lock (domain);
275 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
276 mono_domain_unlock (domain);
278 if (user_data.method) {
279 char *mname = mono_method_full_name (user_data.method, TRUE);
280 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
285 g_print ("No method at %p\n", ip);
289 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
290 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
292 gsctx = mono_jit_info_get_generic_sharing_context (ji);
295 if (gsctx->is_gsharedvt)
296 shared_type = "gsharedvt ";
298 shared_type = "gshared ";
301 g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
304 g_print ("%s:%d\n", source->source_file, source->row);
307 mono_debug_free_source_location (source);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
321 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller->domain_neutral && !callee->domain_neutral)
331 cmethod = jinfo_get_method (caller);
332 if ((cmethod->klass == mono_defaults.appdomain_class) &&
333 (strstr (cmethod->name, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman) {
354 /* This can happen during startup */
355 global_codeman = mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman, size);
360 ptr = mono_code_manager_reserve (global_codeman, size);
366 /* The callback shouldn't take any locks */
368 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
371 mono_code_manager_foreach (global_codeman, func, user_data);
375 #if defined(__native_client_codegen__) && defined(__native_client__)
379 #ifdef __native_client_gc__
380 __nacl_suspend_thread_if_needed();
383 #endif /* __native_client__ */
386 * mono_create_unwind_op:
388 * Create an unwind op with the given parameters.
391 mono_create_unwind_op (int when, int tag, int reg, int val)
393 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
404 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
406 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
409 res->has_context = context != NULL;
411 memcpy (&res->context, context, sizeof (MonoGenericContext));
417 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
419 return mono_jump_info_token_new2 (mp, image, token, NULL);
423 * mono_tramp_info_create:
425 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
426 * of JI, and UNWIND_OPS.
429 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
431 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
433 info->name = g_strdup ((char*)name);
435 info->code_size = code_size;
437 info->unwind_ops = unwind_ops;
443 mono_tramp_info_free (MonoTrampInfo *info)
448 mono_free_unwind_info (info->unwind_ops);
449 if (info->owns_uw_info)
450 g_free (info->uw_info);
455 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
459 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
460 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
461 ji->d.tramp_info = info;
462 ji->is_trampoline = TRUE;
464 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
466 mono_jit_info_table_add (domain, ji);
470 * mono_tramp_info_register:
472 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
477 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
485 domain = mono_get_root_domain ();
487 copy = g_new0 (MonoTrampInfo, 1);
488 copy->code = info->code;
489 copy->code_size = info->code_size;
490 copy->name = g_strdup (info->name);
492 if (info->unwind_ops) {
493 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
494 copy->owns_uw_info = TRUE;
496 /* Trampolines from aot have the unwind ops already encoded */
497 copy->uw_info = info->uw_info;
498 copy->uw_info_len = info->uw_info_len;
502 tramp_infos = g_slist_prepend (tramp_infos, copy);
505 mono_save_trampoline_xdebug_info (info);
506 mono_lldb_save_trampoline_info (info);
508 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
510 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
513 /* Only register trampolines that have unwind infos */
514 if (mono_get_root_domain () && copy->uw_info)
515 register_trampoline_jit_info (domain, copy);
517 if (mono_jit_map_is_enabled ())
518 mono_emit_jit_tramp (info->code, info->code_size, info->name);
520 mono_tramp_info_free (info);
524 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
526 mono_tramp_info_register_internal (info, domain, FALSE);
530 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
532 mono_tramp_info_register_internal (info, domain, TRUE);
536 mono_tramp_info_cleanup (void)
540 for (l = tramp_infos; l; l = l->next) {
541 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
543 mono_tramp_info_free (info);
545 g_slist_free (tramp_infos);
548 /* Register trampolines created before the root domain was created in the jit info tables */
550 register_trampolines (MonoDomain *domain)
554 for (l = tramp_infos; l; l = l->next) {
555 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
557 register_trampoline_jit_info (domain, info);
561 G_GNUC_UNUSED static void
567 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
568 * Set a breakpoint in break_count () to break the last time <x> is done.
570 G_GNUC_UNUSED gboolean
571 mono_debug_count (void)
573 static int count = 0;
574 static gboolean inited;
580 value = g_getenv ("COUNT");
587 int 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);
795 * mono_jit_thread_attach:
797 * Called by Xamarin.Mac and other products. Attach thread to runtime if
798 * needed and switch to @domain.
800 * @return the original domain which needs to be restored, or NULL.
803 mono_jit_thread_attach (MonoDomain *domain)
808 g_assert (!mono_threads_is_coop_enabled ());
811 /* Happens when called from AOTed code which is only used in the root domain. */
812 domain = mono_get_root_domain ();
817 attached = mono_tls_get_jit_tls () != NULL;
820 mono_thread_attach (domain);
823 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
826 orig = mono_domain_get ();
828 mono_domain_set (domain, TRUE);
830 return orig != domain ? orig : NULL;
834 * mono_jit_set_domain:
836 * Set domain to @domain if @domain is not null
839 mono_jit_set_domain (MonoDomain *domain)
841 g_assert (!mono_threads_is_coop_enabled ());
844 mono_domain_set (domain, TRUE);
849 * \param obj exception object
850 * Abort the thread, print exception information and stack trace
853 mono_thread_abort (MonoObject *obj)
855 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
857 /* handle_remove should be eventually called for this thread, too
860 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
861 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
864 mono_invoke_unhandled_exception_hook (obj);
869 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
871 MonoJitTlsData *jit_tls;
874 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
878 jit_tls = g_new0 (MonoJitTlsData, 1);
880 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
881 jit_tls->end_of_stack = stack_start;
883 mono_set_jit_tls (jit_tls);
885 lmf = g_new0 (MonoLMF, 1);
886 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
888 jit_tls->first_lmf = lmf;
890 mono_set_lmf_addr (&jit_tls->lmf);
894 #ifdef MONO_ARCH_HAVE_TLS_INIT
895 mono_arch_tls_init ();
898 mono_setup_altstack (jit_tls);
904 free_jit_tls_data (MonoJitTlsData *jit_tls)
906 mono_arch_free_jit_tls_data (jit_tls);
907 mono_free_altstack (jit_tls);
909 g_free (jit_tls->first_lmf);
914 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
916 MonoThreadInfo *thread;
917 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
918 thread = mono_thread_info_current_unchecked ();
920 thread->jit_data = jit_tls;
922 mono_arch_cpu_init ();
925 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
928 mono_thread_abort_dummy (MonoObject *obj)
930 if (mono_thread_attach_aborted_cb)
931 mono_thread_attach_aborted_cb (obj);
933 mono_thread_abort (obj);
937 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
939 MonoThreadInfo *thread;
940 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
941 thread = mono_thread_info_current_unchecked ();
943 thread->jit_data = jit_tls;
945 mono_arch_cpu_init ();
949 mini_thread_cleanup (MonoNativeThreadId tid)
951 MonoJitTlsData *jit_tls = NULL;
952 MonoThreadInfo *info;
954 info = mono_thread_info_current_unchecked ();
956 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
957 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
958 * not a trivial thing.
960 * The current offender is mono_thread_manage which cleanup threads from the outside.
962 if (info && mono_thread_info_get_tid (info) == tid) {
963 jit_tls = (MonoJitTlsData *)info->jit_data;
964 info->jit_data = NULL;
966 mono_set_jit_tls (NULL);
968 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
969 if (mono_get_lmf ()) {
971 mono_set_lmf_addr (NULL);
974 info = mono_thread_info_lookup (tid);
976 jit_tls = (MonoJitTlsData *)info->jit_data;
977 info->jit_data = NULL;
979 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
983 free_jit_tls_data (jit_tls);
987 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
989 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
993 ji->data.target = target;
999 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1001 static const char* const patch_info_str[] = {
1002 #define PATCH_INFO(a,b) "" #a,
1003 #include "patch-info.h"
1008 mono_ji_type_to_string (MonoJumpInfoType type)
1010 return patch_info_str [type];
1014 mono_print_ji (const MonoJumpInfo *ji)
1017 case MONO_PATCH_INFO_RGCTX_FETCH: {
1018 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1020 printf ("[RGCTX_FETCH ");
1021 mono_print_ji (entry->data);
1022 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1025 case MONO_PATCH_INFO_METHODCONST: {
1026 char *s = mono_method_full_name (ji->data.method, TRUE);
1027 printf ("[METHODCONST - %s]", s);
1031 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1032 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1036 printf ("[%s]", patch_info_str [ji->type]);
1044 mono_ji_type_to_string (MonoJumpInfoType type)
1050 mono_print_ji (const MonoJumpInfo *ji)
1057 * mono_patch_info_dup_mp:
1059 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1062 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1064 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1065 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1067 switch (patch_info->type) {
1068 case MONO_PATCH_INFO_RVA:
1069 case MONO_PATCH_INFO_LDSTR:
1070 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1071 case MONO_PATCH_INFO_LDTOKEN:
1072 case MONO_PATCH_INFO_DECLSEC:
1073 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1074 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1076 case MONO_PATCH_INFO_SWITCH:
1077 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1078 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1079 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1080 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1082 case MONO_PATCH_INFO_RGCTX_FETCH:
1083 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1084 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1085 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1086 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1088 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1089 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1090 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1092 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1093 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1094 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1096 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1097 MonoGSharedVtMethodInfo *info;
1098 MonoGSharedVtMethodInfo *oinfo;
1101 oinfo = patch_info->data.gsharedvt_method;
1102 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1103 res->data.gsharedvt_method = info;
1104 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1105 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1106 for (i = 0; i < oinfo->num_entries; ++i) {
1107 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1108 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1110 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1112 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1113 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1116 case MONO_PATCH_INFO_VIRT_METHOD: {
1117 MonoJumpInfoVirtMethod *info;
1118 MonoJumpInfoVirtMethod *oinfo;
1120 oinfo = patch_info->data.virt_method;
1121 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1122 res->data.virt_method = info;
1123 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1134 mono_patch_info_hash (gconstpointer data)
1136 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1139 case MONO_PATCH_INFO_RVA:
1140 case MONO_PATCH_INFO_LDSTR:
1141 case MONO_PATCH_INFO_LDTOKEN:
1142 case MONO_PATCH_INFO_DECLSEC:
1143 return (ji->type << 8) | ji->data.token->token;
1144 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1145 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1146 case MONO_PATCH_INFO_INTERNAL_METHOD:
1147 return (ji->type << 8) | g_str_hash (ji->data.name);
1148 case MONO_PATCH_INFO_VTABLE:
1149 case MONO_PATCH_INFO_CLASS:
1150 case MONO_PATCH_INFO_IID:
1151 case MONO_PATCH_INFO_ADJUSTED_IID:
1152 case MONO_PATCH_INFO_METHODCONST:
1153 case MONO_PATCH_INFO_METHOD:
1154 case MONO_PATCH_INFO_METHOD_JUMP:
1155 case MONO_PATCH_INFO_IMAGE:
1156 case MONO_PATCH_INFO_ICALL_ADDR:
1157 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1158 case MONO_PATCH_INFO_FIELD:
1159 case MONO_PATCH_INFO_SFLDA:
1160 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1161 case MONO_PATCH_INFO_METHOD_RGCTX:
1162 case MONO_PATCH_INFO_SIGNATURE:
1163 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1164 case MONO_PATCH_INFO_AOT_JIT_INFO:
1165 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1166 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1167 return (ji->type << 8) | (gssize)ji->data.target;
1168 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1169 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1170 case MONO_PATCH_INFO_RGCTX_FETCH:
1171 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1172 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1174 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1176 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1177 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1178 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1179 case MONO_PATCH_INFO_GC_NURSERY_START:
1180 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1181 case MONO_PATCH_INFO_GOT_OFFSET:
1182 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1183 case MONO_PATCH_INFO_AOT_MODULE:
1184 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1185 return (ji->type << 8);
1186 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1187 return (ji->type << 8) | (ji->data.index);
1188 case MONO_PATCH_INFO_SWITCH:
1189 return (ji->type << 8) | ji->data.table->table_size;
1190 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1191 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1192 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1193 /* Hash on the selector name */
1194 return g_str_hash (ji->data.target);
1195 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1196 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1197 case MONO_PATCH_INFO_LDSTR_LIT:
1198 return g_str_hash (ji->data.target);
1199 case MONO_PATCH_INFO_VIRT_METHOD: {
1200 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1202 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1204 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1205 return (ji->type << 8) | g_str_hash (ji->data.target);
1206 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1207 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1209 printf ("info type: %d\n", ji->type);
1210 mono_print_ji (ji); printf ("\n");
1211 g_assert_not_reached ();
1217 * mono_patch_info_equal:
1219 * This might fail to recognize equivalent patches, i.e. floats, so its only
1220 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1224 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1226 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1227 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1229 if (ji1->type != ji2->type)
1232 switch (ji1->type) {
1233 case MONO_PATCH_INFO_RVA:
1234 case MONO_PATCH_INFO_LDSTR:
1235 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1236 case MONO_PATCH_INFO_LDTOKEN:
1237 case MONO_PATCH_INFO_DECLSEC:
1238 if ((ji1->data.token->image != ji2->data.token->image) ||
1239 (ji1->data.token->token != ji2->data.token->token) ||
1240 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1241 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1242 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1245 case MONO_PATCH_INFO_INTERNAL_METHOD:
1246 return g_str_equal (ji1->data.name, ji2->data.name);
1247 case MONO_PATCH_INFO_RGCTX_FETCH:
1248 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1249 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1250 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1252 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);
1254 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1255 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1256 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1258 return c1->sig == c2->sig && c1->method == c2->method;
1260 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1261 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1262 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1263 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;
1264 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1265 return ji1->data.index == ji2->data.index;
1266 case MONO_PATCH_INFO_VIRT_METHOD:
1267 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1268 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1269 if (ji1->data.target == ji2->data.target)
1271 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1272 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1273 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1275 if (ji1->data.target != ji2->data.target)
1284 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1286 unsigned char *ip = patch_info->ip.i + code;
1287 gconstpointer target = NULL;
1291 switch (patch_info->type) {
1292 case MONO_PATCH_INFO_BB:
1294 * FIXME: This could be hit for methods without a prolog. Should use -1
1295 * but too much code depends on a 0 initial value.
1297 //g_assert (patch_info->data.bb->native_offset);
1298 target = patch_info->data.bb->native_offset + code;
1300 case MONO_PATCH_INFO_ABS:
1301 target = patch_info->data.target;
1303 case MONO_PATCH_INFO_LABEL:
1304 target = patch_info->data.inst->inst_c0 + code;
1306 case MONO_PATCH_INFO_IP:
1309 case MONO_PATCH_INFO_METHOD_REL:
1310 target = code + patch_info->data.offset;
1312 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1313 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1315 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1316 g_assert_not_reached ();
1318 target = mono_icall_get_wrapper (mi);
1321 case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
1322 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1324 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1325 g_assert_not_reached ();
1330 case MONO_PATCH_INFO_METHOD_JUMP:
1331 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1332 if (!mono_error_ok (error))
1335 case MONO_PATCH_INFO_METHOD:
1336 if (patch_info->data.method == method) {
1339 /* get the trampoline to the method from the domain */
1340 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1341 if (!mono_error_ok (error))
1345 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1348 mono_domain_lock (domain);
1349 if (!domain_jit_info (domain)->method_code_hash)
1350 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1351 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1353 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1354 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1356 mono_domain_unlock (domain);
1360 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1361 #if defined(__native_client_codegen__)
1362 target = (gpointer)&__nacl_thread_suspension_needed;
1364 g_assert (mono_threads_is_coop_enabled ());
1365 target = (gpointer)&mono_polling_required;
1368 case MONO_PATCH_INFO_SWITCH: {
1369 gpointer *jump_table;
1371 #if defined(__native_client__) && defined(__native_client_codegen__)
1372 /* This memory will leak, but we don't care if we're */
1373 /* not deleting JIT'd methods anyway */
1374 jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
1376 if (method && method->dynamic) {
1377 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1379 if (mono_aot_only) {
1380 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1382 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1387 for (i = 0; i < patch_info->data.table->table_size; i++) {
1388 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1391 target = jump_table;
1394 case MONO_PATCH_INFO_METHODCONST:
1395 case MONO_PATCH_INFO_CLASS:
1396 case MONO_PATCH_INFO_IMAGE:
1397 case MONO_PATCH_INFO_FIELD:
1398 case MONO_PATCH_INFO_SIGNATURE:
1399 case MONO_PATCH_INFO_AOT_MODULE:
1400 target = patch_info->data.target;
1402 case MONO_PATCH_INFO_IID:
1403 mono_class_init (patch_info->data.klass);
1404 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1406 case MONO_PATCH_INFO_ADJUSTED_IID:
1407 mono_class_init (patch_info->data.klass);
1408 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1410 case MONO_PATCH_INFO_VTABLE:
1411 target = mono_class_vtable (domain, patch_info->data.klass);
1414 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1415 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1417 if (del_tramp->is_virtual)
1418 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1420 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1423 case MONO_PATCH_INFO_SFLDA: {
1424 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1426 if (mono_class_field_is_special_static (patch_info->data.field)) {
1427 gpointer addr = NULL;
1429 mono_domain_lock (domain);
1430 if (domain->special_static_fields)
1431 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1432 mono_domain_unlock (domain);
1438 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1439 /* Done by the generated code */
1443 if (!mono_runtime_class_init_full (vtable, error)) {
1448 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1451 case MONO_PATCH_INFO_RVA: {
1452 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1455 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1456 target = mono_image_rva_map (patch_info->data.token->image, rva);
1459 case MONO_PATCH_INFO_R4:
1460 case MONO_PATCH_INFO_R8:
1461 target = patch_info->data.target;
1463 case MONO_PATCH_INFO_EXC_NAME:
1464 target = patch_info->data.name;
1466 case MONO_PATCH_INFO_LDSTR:
1468 mono_ldstr_checked (domain, patch_info->data.token->image,
1469 mono_metadata_token_index (patch_info->data.token->token), error);
1471 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1473 MonoClass *handle_class;
1475 handle = mono_ldtoken_checked (patch_info->data.token->image,
1476 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1477 if (!mono_error_ok (error))
1479 mono_class_init (handle_class);
1480 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1482 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1483 if (!mono_error_ok (error))
1487 case MONO_PATCH_INFO_LDTOKEN: {
1489 MonoClass *handle_class;
1491 handle = mono_ldtoken_checked (patch_info->data.token->image,
1492 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1493 if (!mono_error_ok (error))
1494 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1495 mono_class_init (handle_class);
1500 case MONO_PATCH_INFO_DECLSEC:
1501 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1503 case MONO_PATCH_INFO_ICALL_ADDR:
1504 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1505 /* run_cctors == 0 -> AOT */
1506 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1507 const char *exc_class;
1508 const char *exc_arg;
1511 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1513 if (mono_aot_only) {
1514 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1517 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));
1523 target = mono_lookup_internal_call (patch_info->data.method);
1525 if (!target && run_cctors)
1526 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1529 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1530 target = mono_thread_interruption_request_flag ();
1532 case MONO_PATCH_INFO_METHOD_RGCTX: {
1533 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1536 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1539 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1540 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1542 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1545 case MONO_PATCH_INFO_BB_OVF:
1546 case MONO_PATCH_INFO_EXC_OVF:
1547 case MONO_PATCH_INFO_GOT_OFFSET:
1548 case MONO_PATCH_INFO_NONE:
1550 case MONO_PATCH_INFO_RGCTX_FETCH: {
1551 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1553 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1556 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1557 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1559 /* AOT, not needed */
1562 target = mono_arch_get_seq_point_info (domain, code);
1565 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1566 int card_table_shift_bits;
1567 gpointer card_table_mask;
1569 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1572 case MONO_PATCH_INFO_GC_NURSERY_START: {
1576 target = mono_gc_get_nursery (&shift_bits, &size);
1579 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1583 mono_gc_get_nursery (&shift_bits, &size);
1585 target = (gpointer)(mgreg_t)shift_bits;
1588 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1589 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1592 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1596 case MONO_PATCH_INFO_LDSTR_LIT: {
1600 len = strlen ((const char *)patch_info->data.target);
1601 s = (char *)mono_domain_alloc0 (domain, len + 1);
1602 memcpy (s, patch_info->data.target, len);
1607 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1608 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1610 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1611 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1613 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1614 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1616 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1617 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1623 g_assert_not_reached ();
1626 return (gpointer)target;
1630 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1632 MonoGenericInst *inst;
1635 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1637 if (context && context->class_inst) {
1638 inst = context->class_inst;
1639 for (i = 0; i < inst->type_argc; ++i) {
1640 MonoType *type = inst->type_argv [i];
1642 if (mini_is_gsharedvt_gparam (type))
1643 gsctx->is_gsharedvt = TRUE;
1646 if (context && context->method_inst) {
1647 inst = context->method_inst;
1649 for (i = 0; i < inst->type_argc; ++i) {
1650 MonoType *type = inst->type_argv [i];
1652 if (mini_is_gsharedvt_gparam (type))
1653 gsctx->is_gsharedvt = TRUE;
1659 * LOCKING: Acquires the jit code hash lock.
1662 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1665 static gboolean inited = FALSE;
1666 static int lookups = 0;
1667 static int failed_lookups = 0;
1669 mono_domain_jit_code_hash_lock (domain);
1670 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1671 if (!ji && shared) {
1672 /* Try generic sharing */
1673 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1674 if (ji && !ji->has_generic_jit_info)
1677 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1678 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1686 mono_domain_jit_code_hash_unlock (domain);
1692 lookup_method (MonoDomain *domain, MonoMethod *method)
1697 ji = mini_lookup_method (domain, method, NULL);
1700 if (!mono_method_is_generic_sharable (method, FALSE))
1702 shared = mini_get_shared_method (method);
1703 ji = mini_lookup_method (domain, method, shared);
1710 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1712 return lookup_method (domain, method);
1716 static FILE* perf_map_file;
1719 mono_enable_jit_map (void)
1721 if (!perf_map_file) {
1723 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1725 perf_map_file = fopen (name, "w");
1730 mono_emit_jit_tramp (void *start, int size, const char *desc)
1733 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1737 mono_emit_jit_map (MonoJitInfo *jinfo)
1739 if (perf_map_file) {
1740 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1741 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1747 mono_jit_map_is_enabled (void)
1749 return perf_map_file != NULL;
1755 no_gsharedvt_in_wrapper (void)
1757 g_assert_not_reached ();
1763 Limit JITing to mono_cpu_count
1764 This ensures there's always room for application progress and not just JITing.
1766 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.
1767 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1768 Dependency management in this case is too complex to justify implementing it.
1770 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1773 Get rid of cctor invocatio from within the JIT, it increases JIT duration and complicates things A LOT.
1774 Verify that we don't have too many spurious wakeups.
1775 Experiment with limiting to values around mono_cpu_count +/- 1 as this would enable progress during warmup.
1781 } JitCompilationEntry;
1784 GPtrArray *in_flight_methods; //JitCompilationEntry*
1786 int threads_waiting;
1789 } JitCompilationData;
1791 static JitCompilationData compilation_data;
1792 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1795 mini_jit_init_job_control (void)
1797 mono_coop_mutex_init (&compilation_data.lock);
1798 mono_coop_cond_init (&compilation_data.cond);
1799 compilation_data.in_flight_methods = g_ptr_array_new ();
1803 lock_compilation_data (void)
1805 mono_coop_mutex_lock (&compilation_data.lock);
1809 unlock_compilation_data (void)
1811 mono_coop_mutex_unlock (&compilation_data.lock);
1814 static JitCompilationEntry*
1815 find_method (MonoMethod *method, MonoDomain *domain)
1818 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1819 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1820 if (e->method == method && e->domain == domain)
1828 add_current_thread (MonoJitTlsData *jit_tls)
1830 if (jit_tls->active_jit_methods == 0)
1831 ++compilation_data.active_threads;
1832 ++jit_tls->active_jit_methods;
1835 //Returns true if this thread should wait
1837 should_wait_for_available_cpu_capacity (void)
1839 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1841 //We can't suspend threads that are already JIT'ing something or we risk deadlocking
1842 if (jit_tls->active_jit_methods > 0)
1845 //If there are as many active threads as cores, JITing more will cause thrashing
1846 if (compilation_data.active_threads >= mono_cpu_count ()) {
1847 ++jit_methods_overload;
1854 * Returns true if this method waited successfully for another thread to JIT it
1857 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1859 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1860 JitCompilationEntry *entry;
1862 static gboolean inited;
1864 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1865 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1866 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1867 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1871 lock_compilation_data ();
1874 while (should_wait_for_available_cpu_capacity ()) {
1876 ++compilation_data.threads_waiting;
1877 mono_coop_cond_wait (&compilation_data.cond, &compilation_data.lock);
1878 --compilation_data.threads_waiting;
1880 ++jit_spurious_wakeups;
1884 if (!(entry = find_method (method, domain))) {
1885 entry = g_new (JitCompilationEntry, 1);
1886 entry->method = method;
1887 entry->domain = domain;
1889 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1890 add_current_thread (jit_tls);
1892 unlock_compilation_data ();
1894 } else if (jit_tls->active_jit_methods > 0) {
1895 //We can't suspend the current thread if it's already JITing a method.
1896 //Dependency management is too compilated and we want to get rid of this anyways.
1898 ++jit_methods_multiple;
1899 ++jit_tls->active_jit_methods;
1901 unlock_compilation_data ();
1904 ++jit_methods_waited;
1907 ++compilation_data.threads_waiting;
1908 mono_coop_cond_wait (&compilation_data.cond, &compilation_data.lock);
1909 --compilation_data.threads_waiting;
1911 if (!find_method (method, domain)) {
1912 unlock_compilation_data ();
1915 ++jit_spurious_wakeups;
1922 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1924 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1926 lock_compilation_data ();
1928 g_assert (jit_tls->active_jit_methods > 0);
1929 --jit_tls->active_jit_methods;
1930 if (jit_tls->active_jit_methods == 0)
1931 --compilation_data.active_threads;
1933 JitCompilationEntry *entry = find_method (method, target_domain);
1934 g_assert (entry); // It would be weird to fail
1935 if (--entry->count == 0) {
1936 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1940 if (compilation_data.threads_waiting)
1941 mono_coop_cond_broadcast (&compilation_data.cond);
1942 unlock_compilation_data ();
1947 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1949 MonoDomain *target_domain, *domain = mono_domain_get ();
1951 gpointer code = NULL, p;
1953 MonoJitICallInfo *callinfo = NULL;
1954 WrapperInfo *winfo = NULL;
1958 #ifdef ENABLE_INTERPRETER
1959 if (mono_use_interpreter && !jit_only) {
1960 code = mono_interp_create_method_pointer (method, error);
1967 /* Should be handled by the caller */
1968 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
1971 * ICALL wrappers are handled specially, since there is only one copy of them
1972 * shared by all appdomains.
1974 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1975 winfo = mono_marshal_get_wrapper_info (method);
1976 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
1977 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
1978 g_assert (callinfo);
1980 /* Must be domain neutral since there is only one copy */
1981 opt |= MONO_OPT_SHARED;
1983 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
1984 opt &= ~MONO_OPT_SHARED;
1987 if (opt & MONO_OPT_SHARED)
1988 target_domain = mono_get_root_domain ();
1990 target_domain = domain;
1992 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
1993 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
1996 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
1997 MonoGenericContext *ctx = NULL;
1998 if (method->is_inflated)
1999 ctx = mono_method_get_context (method);
2000 method = info->d.synchronized_inner.method;
2002 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2003 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2009 info = lookup_method (target_domain, method);
2011 /* We can't use a domain specific method in another domain */
2012 if (! ((domain != target_domain) && !info->domain_neutral)) {
2015 mono_jit_stats.methods_lookups++;
2016 vtable = mono_class_vtable_full (domain, method->klass, error);
2020 if (!mono_runtime_class_init_full (vtable, error))
2022 return mono_create_ftnptr (target_domain, info->code_start);
2026 #ifdef MONO_USE_AOT_COMPILER
2027 if (opt & MONO_OPT_AOT) {
2028 MonoDomain *domain = mono_domain_get ();
2030 mono_class_init (method->klass);
2032 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2035 if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
2037 * The suspend code needs to be able to lookup these methods by ip in async context,
2038 * so preload their jit info.
2040 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2045 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2046 * This is not a problem, since it will be initialized when the method is first
2047 * called by init_method ().
2049 if (!mono_llvm_only) {
2050 vtable = mono_class_vtable (domain, method->klass);
2052 if (!mono_runtime_class_init_full (vtable, error))
2061 if (!code && mono_llvm_only) {
2062 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2063 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2065 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2067 * These wrappers are only created for signatures which are in the program, but
2068 * sometimes we load methods too eagerly and have to create them even if they
2069 * will never be called.
2071 return no_gsharedvt_in_wrapper;
2077 if (wait_or_register_method_to_compile (method, target_domain))
2079 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2080 unregister_method_for_compile (method, target_domain);
2082 if (!mono_error_ok (error))
2085 if (!code && mono_llvm_only) {
2086 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2087 g_assert_not_reached ();
2093 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2097 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2099 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2103 p = mono_create_ftnptr (target_domain, code);
2106 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2107 mono_loader_lock ();
2109 if (!callinfo->wrapper) {
2110 callinfo->wrapper = p;
2111 mono_register_jit_icall_wrapper (callinfo, p);
2114 mono_loader_unlock ();
2121 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2125 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2130 * mono_jit_compile_method_jit_only:
2132 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2135 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2139 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2143 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2145 invalidated_delegate_trampoline (char *desc)
2147 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2148 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2154 * mono_jit_free_method:
2156 * Free all memory allocated by the JIT for METHOD.
2159 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2161 MonoJitDynamicMethodInfo *ji;
2162 gboolean destroy = TRUE;
2163 GHashTableIter iter;
2164 MonoJumpList *jlist;
2166 g_assert (method->dynamic);
2168 mono_domain_lock (domain);
2169 ji = mono_dynamic_code_hash_lookup (domain, method);
2170 mono_domain_unlock (domain);
2175 mono_debug_remove_method (method, domain);
2176 mono_lldb_remove_method (domain, method, ji);
2178 mono_domain_lock (domain);
2179 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2180 mono_domain_jit_code_hash_lock (domain);
2181 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2182 mono_domain_jit_code_hash_unlock (domain);
2183 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2185 /* requires the domain lock - took above */
2186 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2188 /* Remove jump targets in this method */
2189 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2190 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2191 GSList *tmp, *remove;
2194 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2195 guint8 *ip = (guint8 *)tmp->data;
2197 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2198 remove = g_slist_prepend (remove, tmp);
2200 for (tmp = remove; tmp; tmp = tmp->next) {
2201 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2203 g_slist_free (remove);
2205 mono_domain_unlock (domain);
2207 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2208 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2210 * Instead of freeing the code, change it to call an error routine
2211 * so people can fix their code.
2213 char *type = mono_type_full_name (&method->klass->byval_arg);
2214 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2217 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2223 * This needs to be done before freeing code_mp, since the code address is the
2224 * key in the table, so if we free the code_mp first, another thread can grab the
2225 * same code address and replace our entry in the table.
2227 mono_jit_info_table_remove (domain, ji->ji);
2230 mono_code_manager_destroy (ji->code_mp);
2235 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2237 MonoDomain *target_domain;
2240 if (default_opt & MONO_OPT_SHARED)
2241 target_domain = mono_get_root_domain ();
2243 target_domain = domain;
2245 info = lookup_method (target_domain, method);
2247 /* We can't use a domain specific method in another domain */
2248 if (! ((domain != target_domain) && !info->domain_neutral)) {
2249 mono_jit_stats.methods_lookups++;
2252 return info->code_start;
2261 static guint32 bisect_opt = 0;
2262 static GHashTable *bisect_methods_hash = NULL;
2265 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2268 char method_name [2048];
2271 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2272 g_assert (bisect_methods_hash);
2274 file = fopen (method_list_filename, "r");
2277 while (fgets (method_name, sizeof (method_name), file)) {
2278 size_t len = strlen (method_name);
2280 g_assert (method_name [len - 1] == '\n');
2281 method_name [len - 1] = 0;
2282 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2284 g_assert (feof (file));
2287 gboolean mono_do_single_method_regression = FALSE;
2288 guint32 mono_single_method_regression_opt = 0;
2289 MonoMethod *mono_current_single_method;
2290 GSList *mono_single_method_list;
2291 GHashTable *mono_single_method_hash;
2294 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2298 if (bisect_methods_hash) {
2299 char *name = mono_method_full_name (method, TRUE);
2300 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2303 return default_opt | bisect_opt;
2305 if (!mono_do_single_method_regression)
2307 if (!mono_current_single_method) {
2308 if (!mono_single_method_hash)
2309 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2310 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2311 g_hash_table_insert (mono_single_method_hash, method, method);
2312 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2316 if (method == mono_current_single_method)
2317 return mono_single_method_regression_opt;
2322 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2324 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2329 gpointer compiled_method;
2330 gpointer runtime_invoke;
2332 MonoDynCallInfo *dyn_call_info;
2333 MonoClass *ret_box_class;
2334 MonoMethodSignature *sig;
2335 gboolean gsharedvt_invoke;
2336 gpointer *wrapper_arg;
2337 } RuntimeInvokeInfo;
2339 static RuntimeInvokeInfo*
2340 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2343 RuntimeInvokeInfo *info;
2345 info = g_new0 (RuntimeInvokeInfo, 1);
2346 info->compiled_method = compiled_method;
2347 if (mono_llvm_only && method->string_ctor)
2348 info->sig = mono_marshal_get_string_ctor_signature (method);
2350 info->sig = mono_method_signature (method);
2352 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2353 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2354 if (!mono_error_ok (error))
2356 g_assert (info->vtable);
2358 MonoMethodSignature *sig = info->sig;
2362 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2363 * in full-aot mode, so we use a slower, but more generic wrapper if
2364 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2366 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2367 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2368 gboolean supported = TRUE;
2371 if (method->string_ctor)
2372 sig = mono_marshal_get_string_ctor_signature (method);
2374 for (i = 0; i < sig->param_count; ++i) {
2375 MonoType *t = sig->params [i];
2377 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2381 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2385 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2389 ret_type = sig->ret;
2390 switch (ret_type->type) {
2391 case MONO_TYPE_VOID:
2403 case MONO_TYPE_BOOLEAN:
2404 case MONO_TYPE_CHAR:
2407 info->ret_box_class = mono_class_from_mono_type (ret_type);
2410 info->ret_box_class = mono_defaults.int_class;
2412 case MONO_TYPE_STRING:
2413 case MONO_TYPE_CLASS:
2414 case MONO_TYPE_ARRAY:
2415 case MONO_TYPE_SZARRAY:
2416 case MONO_TYPE_OBJECT:
2418 case MONO_TYPE_GENERICINST:
2419 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2420 info->ret_box_class = mono_class_from_mono_type (ret_type);
2422 case MONO_TYPE_VALUETYPE:
2423 info->ret_box_class = mono_class_from_mono_type (ret_type);
2426 g_assert_not_reached ();
2430 if (!info->dyn_call_info) {
2431 if (mono_llvm_only) {
2432 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2433 g_assert_not_reached ();
2435 info->gsharedvt_invoke = TRUE;
2436 if (!callee_gsharedvt) {
2437 /* Invoke a gsharedvt out wrapper instead */
2438 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2439 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2441 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2442 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2444 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2445 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2446 g_free (wrapper_sig);
2448 info->compiled_method = mono_jit_compile_method (wrapper, error);
2449 if (!mono_error_ok (error)) {
2454 /* Gsharedvt methods can be invoked the same way */
2455 /* The out wrapper has the same signature as the compiled gsharedvt method */
2456 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2458 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2460 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2461 g_free (wrapper_sig);
2464 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2465 if (!mono_error_ok (error)) {
2475 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2477 MonoMethodSignature *sig = info->sig;
2478 MonoDomain *domain = mono_domain_get ();
2479 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2481 gpointer retval_ptr;
2482 guint8 retval [256];
2483 gpointer *param_refs;
2488 g_assert (info->gsharedvt_invoke);
2491 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2492 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2493 * signatures, so we only have to generate runtime invoke wrappers for these
2495 * This code also handles invocation of gsharedvt methods directly, no
2496 * out wrappers are used in that case.
2498 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2499 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2502 * The runtime invoke wrappers expects pointers to primitive types, so have to
2506 args [pindex ++] = &obj;
2507 if (sig->ret->type != MONO_TYPE_VOID) {
2508 retval_ptr = (gpointer)&retval;
2509 args [pindex ++] = &retval_ptr;
2511 for (i = 0; i < sig->param_count; ++i) {
2512 MonoType *t = sig->params [i];
2514 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2515 MonoClass *klass = mono_class_from_mono_type (t);
2516 guint8 *nullable_buf;
2519 size = mono_class_value_size (klass, NULL);
2520 nullable_buf = g_alloca (size);
2521 g_assert (nullable_buf);
2523 /* The argument pointed to by params [i] is either a boxed vtype or null */
2524 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2525 params [i] = nullable_buf;
2528 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2529 param_refs [i] = params [i];
2530 params [i] = &(param_refs [i]);
2532 args [pindex ++] = ¶ms [i];
2534 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2535 args [pindex ++] = &info->wrapper_arg;
2537 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2539 runtime_invoke (NULL, args, exc, info->compiled_method);
2543 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2544 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2546 return *(MonoObject**)retval;
2550 * mono_jit_runtime_invoke:
2551 * \param method: the method to invoke
2552 * \param obj: this pointer
2553 * \param params: array of parameter values.
2554 * \param exc: Set to the exception raised in the managed method.
2555 * \param error: error or caught exception object
2556 * If \p exc is NULL, \p error is thrown instead.
2557 * If coop is enabled, \p exc argument is ignored -
2558 * all exceptions are caught and propagated through \p error
2561 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2563 MonoMethod *invoke, *callee;
2564 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2565 MonoDomain *domain = mono_domain_get ();
2566 MonoJitDomainInfo *domain_info;
2567 RuntimeInvokeInfo *info, *info2;
2568 MonoJitInfo *ji = NULL;
2569 gboolean callee_gsharedvt = FALSE;
2571 #ifdef ENABLE_INTERPRETER
2572 if (mono_use_interpreter)
2573 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2578 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2579 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2583 domain_info = domain_jit_info (domain);
2585 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2588 if (mono_security_core_clr_enabled ()) {
2590 * This might be redundant since mono_class_vtable () already does this,
2591 * but keep it just in case for moonlight.
2593 mono_class_setup_vtable (method->klass);
2594 if (mono_class_has_failure (method->klass)) {
2595 mono_error_set_for_class_failure (error, method->klass);
2597 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2602 gpointer compiled_method;
2605 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2606 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2608 * Array Get/Set/Address methods. The JIT implements them using inline code
2609 * inside the runtime invoke wrappers, so no need to compile them.
2611 if (mono_aot_only) {
2613 * Call a wrapper, since the runtime invoke wrapper was not generated.
2615 MonoMethod *wrapper;
2617 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2618 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2626 compiled_method = mono_jit_compile_method (callee, error);
2627 if (!compiled_method) {
2628 g_assert (!mono_error_ok (error));
2632 if (mono_llvm_only) {
2633 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2634 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2635 if (callee_gsharedvt)
2636 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2639 if (!callee_gsharedvt)
2640 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2642 compiled_method = NULL;
2645 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2646 if (!mono_error_ok (error))
2649 mono_domain_lock (domain);
2650 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2651 mono_domain_unlock (domain);
2659 * We need this here because mono_marshal_get_runtime_invoke can place
2660 * the helper method in System.Object and not the target class.
2662 if (!mono_runtime_class_init_full (info->vtable, error)) {
2664 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2668 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2669 we always catch the exception and propagate it through the MonoError */
2670 gboolean catchExcInMonoError =
2671 (exc == NULL) && mono_threads_is_coop_enabled ();
2672 MonoObject *invoke_exc = NULL;
2673 if (catchExcInMonoError)
2676 /* The wrappers expect this to be initialized to NULL */
2680 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2681 if (info->dyn_call_info) {
2682 MonoMethodSignature *sig = mono_method_signature (method);
2684 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2687 guint8 retval [256];
2689 if (!dyn_runtime_invoke) {
2690 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2691 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2692 if (!mono_error_ok (error))
2696 /* Convert the arguments to the format expected by start_dyn_call () */
2697 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2700 args [pindex ++] = &obj;
2701 for (i = 0; i < sig->param_count; ++i) {
2702 MonoType *t = sig->params [i];
2705 args [pindex ++] = ¶ms [i];
2706 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2707 args [pindex ++] = ¶ms [i];
2709 args [pindex ++] = params [i];
2713 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2715 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2717 dyn_runtime_invoke (buf, exc, info->compiled_method);
2718 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2720 if (catchExcInMonoError && *exc != NULL) {
2721 mono_error_set_exception_instance (error, (MonoException*) *exc);
2725 if (info->ret_box_class)
2726 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2728 return *(MonoObject**)retval;
2734 if (mono_llvm_only) {
2735 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2739 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2741 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2743 if (catchExcInMonoError && *exc != NULL)
2744 mono_error_set_exception_instance (error, (MonoException*) *exc);
2753 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2756 * mini_llvmonly_initial_imt_tramp:
2758 * This function is called the first time a call is made through an IMT trampoline.
2759 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2762 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2764 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2769 mono_vtable_build_imt_slot (info->vtable, info->slot);
2771 imt = (gpointer*)info->vtable;
2772 imt -= MONO_IMT_SIZE;
2774 /* Return what the real IMT trampoline returns */
2775 ftndesc = imt [info->slot];
2778 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2779 /* Happens when the imt slot contains only a generic virtual method */
2781 return func ((gpointer *)ftndesc [1], imt_method);
2784 /* This is called indirectly through an imt slot. */
2786 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2790 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2791 while (arg [i] && arg [i] != imt_method)
2798 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2800 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2802 //g_assert (arg [0] == imt_method);
2807 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2809 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2810 if (arg [0] == imt_method)
2817 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2819 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2820 if (arg [0] == imt_method)
2822 else if (arg [2] == imt_method)
2829 * A version of the imt trampoline used for generic virtual/variant iface methods.
2830 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2831 * in the search table. The original JIT code had a 'fallback' trampoline it could
2832 * call, but we can't do that, so we just return NULL, and the compiled code
2836 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2840 while (arg [i] && arg [i] != imt_method)
2849 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2853 int i, index, real_count;
2854 gboolean virtual_generic = FALSE;
2857 * Create an array which is passed to the imt trampoline functions.
2858 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2862 for (i = 0; i < count; ++i) {
2863 MonoIMTCheckItem *item = imt_entries [i];
2865 if (item->is_equals)
2867 if (item->has_target_code)
2868 virtual_generic = TRUE;
2872 * Initialize all vtable entries reachable from this imt slot, so the compiled
2873 * code doesn't have to check it.
2875 for (i = 0; i < count; ++i) {
2876 MonoIMTCheckItem *item = imt_entries [i];
2879 if (!item->is_equals || item->has_target_code)
2881 vt_slot = item->value.vtable_slot;
2882 mono_init_vtable_slot (vtable, vt_slot);
2885 /* Save the entries into an array */
2886 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2888 for (i = 0; i < count; ++i) {
2889 MonoIMTCheckItem *item = imt_entries [i];
2891 if (!item->is_equals)
2894 g_assert (item->key);
2895 buf [(index * 2)] = item->key;
2896 if (item->has_target_code)
2897 buf [(index * 2) + 1] = item->value.target_code;
2899 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2902 buf [(index * 2)] = NULL;
2903 buf [(index * 2) + 1] = fail_tramp;
2906 * Return a function descriptor for a C function with 'buf' as its argument.
2907 * It will by called by JITted code.
2909 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2910 switch (real_count) {
2912 res [0] = mono_llvmonly_imt_tramp_1;
2915 res [0] = mono_llvmonly_imt_tramp_2;
2918 res [0] = mono_llvmonly_imt_tramp_3;
2921 res [0] = mono_llvmonly_imt_tramp;
2924 if (virtual_generic || fail_tramp)
2925 res [0] = mono_llvmonly_fallback_imt_tramp;
2931 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2933 MonoException *exc = NULL;
2935 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2936 MONO_SIG_HANDLER_GET_CONTEXT;
2938 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2940 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2942 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2943 if (mono_arch_is_int_overflow (ctx, info))
2945 * The spec says this throws ArithmeticException, but MS throws the derived
2946 * OverflowException.
2948 exc = mono_get_exception_overflow ();
2950 exc = mono_get_exception_divide_by_zero ();
2952 exc = mono_get_exception_divide_by_zero ();
2956 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
2959 mono_handle_native_crash ("SIGFPE", ctx, info);
2960 if (mono_do_crash_chaining) {
2961 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
2966 mono_arch_handle_exception (ctx, exc);
2969 MONO_EXIT_GC_UNSAFE_UNBALANCED;
2972 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
2974 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2975 MONO_SIG_HANDLER_GET_CONTEXT;
2977 if (mono_runtime_get_no_exec ())
2981 mono_handle_native_crash ("SIGILL", ctx, info);
2982 if (mono_do_crash_chaining) {
2983 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
2987 g_assert_not_reached ();
2990 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
2991 #define HAVE_SIG_INFO
2994 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
2997 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2998 gpointer fault_addr = NULL;
2999 #ifdef HAVE_SIG_INFO
3000 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3004 MONO_SIG_HANDLER_GET_CONTEXT;
3006 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3007 if (mono_arch_is_single_step_event (info, ctx)) {
3008 mono_debugger_agent_single_step_event (ctx);
3010 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3011 mono_debugger_agent_breakpoint_hit (ctx);
3016 #if defined(HAVE_SIG_INFO)
3017 #if !defined(HOST_WIN32)
3018 fault_addr = info->si_addr;
3019 if (mono_aot_is_pagefault (info->si_addr)) {
3020 mono_aot_handle_pagefault (info->si_addr);
3025 /* The thread might no be registered with the runtime */
3026 if (!mono_domain_get () || !jit_tls) {
3027 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3029 mono_handle_native_crash ("SIGSEGV", ctx, info);
3030 if (mono_do_crash_chaining) {
3031 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3037 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3039 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3040 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3043 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3044 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3045 fault_addr = info->si_addr;
3046 if (fault_addr == NULL) {
3049 mono_sigctx_to_monoctx (ctx, &mctx);
3051 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3055 if (jit_tls->stack_size &&
3056 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3058 * The hard-guard page has been hit: there is not much we can do anymore
3059 * Print a hopefully clear message and abort.
3061 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3062 g_assert_not_reached ();
3064 /* The original handler might not like that it is executed on an altstack... */
3065 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3068 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3073 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3076 mono_handle_native_crash ("SIGSEGV", ctx, info);
3078 if (mono_do_crash_chaining) {
3079 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3084 mono_arch_handle_exception (ctx, NULL);
3088 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3091 MONO_SIG_HANDLER_GET_CONTEXT;
3093 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3095 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3097 mono_arch_handle_exception (ctx, exc);
3099 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3102 #ifndef DISABLE_REMOTING
3103 /* mono_jit_create_remoting_trampoline:
3104 * @method: pointer to the method info
3106 * Creates a trampoline which calls the remoting functions. This
3107 * is used in the vtable of transparent proxies.
3109 * Returns: a pointer to the newly created code
3112 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3115 guint8 *addr = NULL;
3119 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3120 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3124 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3125 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3126 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3129 addr = (guint8 *)mono_compile_method_checked (nm, error);
3130 return_val_if_nok (error, NULL);
3131 return mono_get_addr_from_ftnptr (addr);
3135 static G_GNUC_UNUSED void
3136 no_imt_trampoline (void)
3138 g_assert_not_reached ();
3141 static G_GNUC_UNUSED void
3142 no_vcall_trampoline (void)
3144 g_assert_not_reached ();
3147 static gpointer *vtable_trampolines;
3148 static int vtable_trampolines_size;
3151 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3153 int index = slot_index + MONO_IMT_SIZE;
3155 if (mono_llvm_only) {
3156 if (slot_index < 0) {
3157 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3158 // FIXME: Memory management
3159 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3160 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3163 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3165 mono_memory_barrier ();
3172 g_assert (slot_index >= - MONO_IMT_SIZE);
3173 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3175 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3179 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3180 while (new_size <= index)
3182 new_table = g_new0 (gpointer, new_size);
3184 if (vtable_trampolines)
3185 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3186 g_free (vtable_trampolines);
3187 mono_memory_barrier ();
3188 vtable_trampolines = (void **)new_table;
3189 vtable_trampolines_size = new_size;
3194 if (!vtable_trampolines [index])
3195 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3196 return vtable_trampolines [index];
3200 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3202 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3206 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3211 gpointer *imt = (gpointer*)vt;
3212 imt -= MONO_IMT_SIZE;
3214 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3218 is_callee_gsharedvt_variable (gpointer addr)
3221 gboolean callee_gsharedvt;
3223 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3225 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3226 if (callee_gsharedvt)
3227 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3228 return callee_gsharedvt;
3232 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3234 gpointer arg = NULL;
3236 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3237 arg = mini_method_get_rgctx (method);
3240 * Avoid adding gsharedvt in wrappers since they might not exist if
3241 * this delegate is called through a gsharedvt delegate invoke wrapper.
3242 * Instead, encode that the method is gsharedvt in del->extra_arg,
3243 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3245 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3246 g_assert ((((mgreg_t)arg) & 1) == 0);
3247 arg = (gpointer)(((mgreg_t)arg) | 1);
3253 mini_init_delegate (MonoDelegate *del)
3256 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3257 #ifdef ENABLE_INTERPRETER
3258 if (mono_use_interpreter)
3259 mono_interp_init_delegate (del);
3264 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3268 abs_offset = offset;
3270 abs_offset = - abs_offset;
3271 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3275 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3277 gboolean is_virtual_generic, is_interface, load_imt_reg;
3280 static guint8 **cache = NULL;
3281 static int cache_size = 0;
3286 if (MONO_TYPE_ISSTRUCT (sig->ret))
3289 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3290 is_interface = mono_class_is_interface (method->klass);
3291 load_imt_reg = is_virtual_generic || is_interface;
3294 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3296 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3298 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3299 g_assert (idx >= 0);
3301 /* Resize the cache to idx + 1 */
3302 if (cache_size < idx + 1) {
3304 if (cache_size < idx + 1) {
3306 int new_cache_size = idx + 1;
3308 new_cache = g_new0 (guint8*, new_cache_size);
3310 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3313 mono_memory_barrier ();
3315 cache_size = new_cache_size;
3323 /* FIXME Support more cases */
3324 if (mono_aot_only) {
3325 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3326 g_assert (cache [idx]);
3328 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3334 * mini_parse_debug_option:
3335 * @option: The option to parse.
3337 * Parses debug options for the mono runtime. The options are the same as for
3338 * the MONO_DEBUG environment variable.
3342 mini_parse_debug_option (const char *option)
3344 if (!strcmp (option, "handle-sigint"))
3345 debug_options.handle_sigint = TRUE;
3346 else if (!strcmp (option, "keep-delegates"))
3347 debug_options.keep_delegates = TRUE;
3348 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3349 debug_options.reverse_pinvoke_exceptions = TRUE;
3350 else if (!strcmp (option, "collect-pagefault-stats"))
3351 debug_options.collect_pagefault_stats = TRUE;
3352 else if (!strcmp (option, "break-on-unverified"))
3353 debug_options.break_on_unverified = TRUE;
3354 else if (!strcmp (option, "no-gdb-backtrace"))
3355 debug_options.no_gdb_backtrace = TRUE;
3356 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3357 debug_options.suspend_on_native_crash = TRUE;
3358 else if (!strcmp (option, "suspend-on-exception"))
3359 debug_options.suspend_on_exception = TRUE;
3360 else if (!strcmp (option, "suspend-on-unhandled"))
3361 debug_options.suspend_on_unhandled = TRUE;
3362 else if (!strcmp (option, "dont-free-domains"))
3363 mono_dont_free_domains = TRUE;
3364 else if (!strcmp (option, "dyn-runtime-invoke"))
3365 debug_options.dyn_runtime_invoke = TRUE;
3366 else if (!strcmp (option, "gdb"))
3367 debug_options.gdb = TRUE;
3368 else if (!strcmp (option, "lldb"))
3369 debug_options.lldb = TRUE;
3370 else if (!strcmp (option, "explicit-null-checks"))
3371 debug_options.explicit_null_checks = TRUE;
3372 else if (!strcmp (option, "gen-seq-points"))
3373 debug_options.gen_sdb_seq_points = TRUE;
3374 else if (!strcmp (option, "gen-compact-seq-points"))
3375 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3376 else if (!strcmp (option, "no-compact-seq-points"))
3377 debug_options.no_seq_points_compact_data = TRUE;
3378 else if (!strcmp (option, "single-imm-size"))
3379 debug_options.single_imm_size = TRUE;
3380 else if (!strcmp (option, "init-stacks"))
3381 debug_options.init_stacks = TRUE;
3382 else if (!strcmp (option, "casts"))
3383 debug_options.better_cast_details = TRUE;
3384 else if (!strcmp (option, "soft-breakpoints"))
3385 debug_options.soft_breakpoints = TRUE;
3386 else if (!strcmp (option, "check-pinvoke-callconv"))
3387 debug_options.check_pinvoke_callconv = TRUE;
3388 else if (!strcmp (option, "use-fallback-tls"))
3389 debug_options.use_fallback_tls = TRUE;
3390 else if (!strcmp (option, "debug-domain-unload"))
3391 mono_enable_debug_domain_unload (TRUE);
3392 else if (!strcmp (option, "partial-sharing"))
3393 mono_set_partial_sharing_supported (TRUE);
3394 else if (!strcmp (option, "align-small-structs"))
3395 mono_align_small_structs = TRUE;
3396 else if (!strcmp (option, "native-debugger-break"))
3397 debug_options.native_debugger_break = TRUE;
3398 else if (!strcmp (option, "disable_omit_fp"))
3399 debug_options.disable_omit_fp = TRUE;
3407 mini_parse_debug_options (void)
3409 char *options = g_getenv ("MONO_DEBUG");
3410 gchar **args, **ptr;
3415 args = g_strsplit (options, ",", -1);
3418 for (ptr = args; ptr && *ptr; ptr++) {
3419 const char *arg = *ptr;
3421 if (!mini_parse_debug_option (arg)) {
3422 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3423 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");
3432 mini_get_debug_options (void)
3434 return &debug_options;
3438 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3440 #if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3443 gpointer* desc = NULL;
3445 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3448 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
3452 # elif defined(__ppc64__) || defined(__powerpc64__)
3454 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3460 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3466 mini_get_addr_from_ftnptr (gpointer descr)
3468 #if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3469 return *(gpointer*)descr;
3476 register_jit_stats (void)
3478 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3479 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3480 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3481 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3482 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3483 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3484 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);
3485 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3486 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3487 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3488 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3489 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3490 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3491 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3492 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3493 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3494 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3495 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3496 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3497 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3498 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3499 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3500 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3501 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3502 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3503 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3504 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3505 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3506 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3507 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3508 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3509 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3510 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3511 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3512 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3513 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3514 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3515 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3516 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3517 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3518 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3519 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3520 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3521 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3522 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3523 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3524 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3525 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3526 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3527 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3528 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3529 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3530 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3531 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3532 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3533 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3534 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3535 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3536 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3537 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3538 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3541 static void runtime_invoke_info_free (gpointer value);
3544 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3546 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3547 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3549 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3553 class_method_pair_hash (gconstpointer data)
3555 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3557 return (gsize)pair->klass ^ (gsize)pair->method;
3561 mini_create_jit_domain_info (MonoDomain *domain)
3563 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3565 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3566 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3567 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3568 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3569 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3570 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3571 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3572 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3573 mono_jit_code_hash_init (&info->interp_code_hash);
3575 domain->runtime_info = info;
3579 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3581 MonoJumpList *jlist = (MonoJumpList *)value;
3582 g_slist_free (jlist->list);
3586 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3588 GSList *list = (GSList *)value;
3589 g_slist_free (list);
3593 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3595 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3596 mono_code_manager_destroy (di->code_mp);
3601 runtime_invoke_info_free (gpointer value)
3603 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3605 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3606 if (info->dyn_call_info)
3607 mono_arch_dyn_call_free (info->dyn_call_info);
3613 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3615 g_slist_free (value);
3619 mini_free_jit_domain_info (MonoDomain *domain)
3621 MonoJitDomainInfo *info = domain_jit_info (domain);
3623 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3624 g_hash_table_destroy (info->jump_target_hash);
3625 if (info->jump_target_got_slot_hash) {
3626 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3627 g_hash_table_destroy (info->jump_target_got_slot_hash);
3629 if (info->dynamic_code_hash) {
3630 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3631 g_hash_table_destroy (info->dynamic_code_hash);
3633 if (info->method_code_hash)
3634 g_hash_table_destroy (info->method_code_hash);
3635 g_hash_table_destroy (info->jump_trampoline_hash);
3636 g_hash_table_destroy (info->jit_trampoline_hash);
3637 g_hash_table_destroy (info->delegate_trampoline_hash);
3638 if (info->static_rgctx_trampoline_hash)
3639 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3640 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3641 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3642 g_hash_table_destroy (info->seq_points);
3643 g_hash_table_destroy (info->arch_seq_points);
3644 if (info->agent_info)
3645 mono_debugger_agent_free_domain_info (domain);
3646 if (info->gsharedvt_arg_tramp_hash)
3647 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3648 if (info->llvm_jit_callees) {
3649 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3650 g_hash_table_destroy (info->llvm_jit_callees);
3653 mono_llvm_free_domain_info (domain);
3656 g_free (domain->runtime_info);
3657 domain->runtime_info = NULL;
3660 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3663 code_manager_chunk_new (void *chunk, int size)
3665 mono_arch_code_chunk_new (chunk, size);
3669 code_manager_chunk_destroy (void *chunk)
3671 mono_arch_code_chunk_destroy (chunk);
3678 llvm_init_inner (void)
3680 if (!mono_llvm_load (NULL))
3691 * Load and initialize LLVM support.
3692 * Return TRUE on success.
3695 mini_llvm_init (void)
3698 static gboolean llvm_inited;
3699 static gboolean init_result;
3701 mono_loader_lock_if_inited ();
3703 init_result = llvm_init_inner ();
3706 mono_loader_unlock_if_inited ();
3714 mini_profiler_enable_with_options (const char* profile_options)
3716 mini_enable_profiler = TRUE;
3717 mini_profiler_options = g_strdup (profile_options);
3721 mini_init (const char *filename, const char *runtime_version)
3725 MonoRuntimeCallbacks callbacks;
3726 MonoThreadInfoRuntimeCallbacks ticallbacks;
3727 MonoCodeManagerCallbacks code_manager_callbacks;
3729 MONO_VES_INIT_BEGIN ();
3731 CHECKED_MONO_INIT ();
3733 #if defined(__linux__) && !defined(__native_client__)
3734 if (access ("/proc/self/maps", F_OK) != 0) {
3735 g_print ("Mono requires /proc to be mounted.\n");
3740 mono_os_mutex_init_recursive (&jit_mutex);
3742 mono_cross_helpers_run ();
3744 mono_counters_init ();
3748 mini_jit_init_job_control ();
3750 /* Happens when using the embedding interface */
3751 if (!default_opt_set)
3752 default_opt = mono_parse_default_optimizations (NULL);
3754 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3756 mono_set_generic_sharing_vt_supported (TRUE);
3759 mono_set_generic_sharing_vt_supported (TRUE);
3762 mono_tls_init_runtime_keys ();
3764 if (!global_codeman)
3765 global_codeman = mono_code_manager_new ();
3767 memset (&callbacks, 0, sizeof (callbacks));
3768 callbacks.create_ftnptr = mini_create_ftnptr;
3769 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3770 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3771 callbacks.set_cast_details = mono_set_cast_details;
3772 callbacks.debug_log = mono_debugger_agent_debug_log;
3773 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3774 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3775 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3776 callbacks.imt_entry_inited = mini_imt_entry_inited;
3777 callbacks.init_delegate = mini_init_delegate;
3778 #define JIT_INVOKE_WORKS
3779 #ifdef JIT_INVOKE_WORKS
3780 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3782 #define JIT_TRAMPOLINES_WORK
3783 #ifdef JIT_TRAMPOLINES_WORK
3784 callbacks.compile_method = mono_jit_compile_method;
3785 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3786 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3787 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3788 callbacks.free_method = mono_jit_free_method;
3789 #ifndef DISABLE_REMOTING
3790 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3794 mono_install_callbacks (&callbacks);
3796 memset (&ticallbacks, 0, sizeof (ticallbacks));
3797 ticallbacks.setup_async_callback = mono_setup_async_callback;
3798 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3799 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3800 ticallbacks.thread_state_init = mono_thread_state_init;
3803 mono_w32handle_init ();
3806 mono_threads_runtime_init (&ticallbacks);
3808 if (g_hasenv ("MONO_DEBUG")) {
3809 mini_parse_debug_options ();
3812 mono_code_manager_init ();
3814 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3815 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3816 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3817 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3819 mono_code_manager_install_callbacks (&code_manager_callbacks);
3823 mono_arch_cpu_init ();
3827 mono_unwind_init ();
3829 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3830 mono_lldb_init ("");
3831 mono_dont_free_domains = TRUE;
3834 #ifdef XDEBUG_ENABLED
3835 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3837 mono_xdebug_init (mono_xdebug);
3838 g_free (mono_xdebug);
3839 /* So methods for multiple domains don't have the same address */
3840 mono_dont_free_domains = TRUE;
3841 mono_using_xdebug = TRUE;
3842 } else if (mini_get_debug_options ()->gdb) {
3843 mono_xdebug_init ((char*)"gdb");
3844 mono_dont_free_domains = TRUE;
3845 mono_using_xdebug = TRUE;
3850 if (mono_use_llvm) {
3851 if (!mono_llvm_load (NULL)) {
3852 mono_use_llvm = FALSE;
3853 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3860 mono_trampolines_init ();
3862 if (default_opt & MONO_OPT_AOT)
3865 mono_debugger_agent_init ();
3867 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3868 mono_set_generic_sharing_supported (TRUE);
3871 mono_threads_signals_init ();
3873 #ifndef MONO_CROSS_COMPILE
3874 mono_runtime_install_handlers ();
3876 mono_threads_install_cleanup (mini_thread_cleanup);
3878 #ifdef JIT_TRAMPOLINES_WORK
3879 mono_install_create_domain_hook (mini_create_jit_domain_info);
3880 mono_install_free_domain_hook (mini_free_jit_domain_info);
3882 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3883 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3884 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3886 if (mini_profiler_enabled ()) {
3887 mono_profiler_load (mini_profiler_get_options ());
3888 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3891 if (debug_options.collect_pagefault_stats)
3892 mono_aot_set_make_unreadable (TRUE);
3894 if (runtime_version)
3895 domain = mono_init_version (filename, runtime_version);
3897 domain = mono_init_from_assembly (filename, filename);
3899 if (mono_aot_only) {
3900 /* This helps catch code allocation requests */
3901 mono_code_manager_set_read_only (domain->code_mp);
3902 mono_marshal_use_aot_wrappers (TRUE);
3905 if (mono_llvm_only) {
3906 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3907 mono_set_always_build_imt_trampolines (TRUE);
3908 } else if (mono_aot_only) {
3909 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3911 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3914 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3915 mono_arch_finish_init ();
3919 /* This must come after mono_init () in the aot-only case */
3920 mono_exceptions_init ();
3922 /* This should come after mono_init () too */
3926 mono_create_helper_signatures ();
3929 register_jit_stats ();
3931 #define JIT_CALLS_WORK
3932 #ifdef JIT_CALLS_WORK
3933 /* Needs to be called here since register_jit_icall depends on it */
3934 mono_marshal_init ();
3936 mono_arch_register_lowlevel_calls ();
3940 mono_generic_sharing_init ();
3943 #ifdef MONO_ARCH_SIMD_INTRINSICS
3944 mono_simd_intrinsics_init ();
3947 mono_tasklets_init ();
3949 register_trampolines (domain);
3951 if (mono_compile_aot)
3953 * Avoid running managed code when AOT compiling, since the platform
3954 * might only support aot-only execution.
3956 mono_runtime_set_no_exec (TRUE);
3958 mono_mem_account_register_counters ();
3960 #define JIT_RUNTIME_WORKS
3961 #ifdef JIT_RUNTIME_WORKS
3962 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
3963 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
3964 mono_error_assert_ok (&error);
3965 mono_thread_attach (domain);
3968 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
3969 mono_runtime_setup_stat_profiler ();
3971 mono_profiler_runtime_initialized ();
3973 MONO_VES_INIT_END ();
3979 register_icalls (void)
3981 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
3982 ves_icall_get_frame_info);
3983 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
3984 ves_icall_get_trace);
3985 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
3986 mono_runtime_install_handlers);
3987 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
3988 mono_runtime_cleanup_handlers);
3990 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
3991 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
3992 mono_debugger_agent_unhandled_exception);
3996 * It's important that we pass `TRUE` as the last argument here, as
3997 * it causes the JIT to omit a wrapper for these icalls. If the JIT
3998 * *did* emit a wrapper, we'd be looking at infinite recursion since
3999 * the wrapper would call the icall which would call the wrapper and
4002 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4003 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4005 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4006 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4007 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4008 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4009 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4010 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4012 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4013 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4014 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4015 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4016 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4017 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4018 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4019 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4020 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4022 // FIXME: This is broken
4023 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4026 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4027 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4028 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4029 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4030 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4031 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4033 #if defined(__native_client__) || defined(__native_client_codegen__)
4034 register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
4037 if (mono_threads_is_coop_enabled ())
4038 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4040 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4041 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4042 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4043 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4044 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4045 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4047 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4048 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4049 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4052 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4053 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4054 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4055 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4058 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4059 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4060 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4061 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4062 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4065 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4066 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4069 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4070 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4071 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4074 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4075 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4078 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4079 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4080 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4081 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4082 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4083 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4084 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4087 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4088 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4089 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4092 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4093 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);
4095 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4096 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4098 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4099 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4101 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4102 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);
4104 #ifdef MONO_ARCH_EMULATE_FREM
4105 #if !defined(__native_client__)
4106 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4107 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4109 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
4113 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4114 if (mono_arch_is_soft_float ()) {
4115 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4116 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4117 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4118 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4119 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4120 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4121 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4122 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4123 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4124 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4125 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4126 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4128 #if SIZEOF_VOID_P == 4
4129 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4132 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4133 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4134 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4135 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4136 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4137 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4138 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4139 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4140 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4141 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4143 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4144 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4145 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4146 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4147 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4149 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4150 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4151 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4152 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4155 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4157 #ifdef COMPRESSED_INTERFACE_BITMAP
4158 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4161 #if SIZEOF_REGISTER == 4
4162 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4164 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4167 /* other jit icalls */
4168 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4169 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4170 "ptr ptr ptr", FALSE);
4171 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4172 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4173 "ptr ptr ptr ptr", FALSE);
4174 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4175 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4176 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4177 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4178 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4179 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4180 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4181 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4182 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4183 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4184 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4185 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4186 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4187 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4188 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4189 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4190 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4191 register_icall (mono_break, "mono_break", NULL, TRUE);
4192 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4193 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4194 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4195 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4196 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4197 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4198 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4199 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4200 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4201 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4202 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4204 register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
4206 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4207 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4208 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4209 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4210 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4212 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4214 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4215 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4216 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4217 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4219 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4220 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4221 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4222 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4223 /* This needs a wrapper so it can have a preserveall cconv */
4224 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4225 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4226 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4227 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4228 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4229 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4230 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4232 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4233 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4234 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4235 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4238 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4240 /* Register tls icalls */
4241 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4242 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4243 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4244 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4245 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4246 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4247 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4248 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4249 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4250 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4253 MonoJitStats mono_jit_stats = {0};
4256 print_jit_stats (void)
4258 if (mono_jit_stats.enabled) {
4259 g_print ("Mono Jit statistics\n");
4260 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4261 mono_jit_stats.max_ratio_method);
4262 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4263 mono_jit_stats.biggest_method);
4265 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4266 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4267 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4268 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4269 g_print ("Methods: %ld\n", mono_stats.method_count);
4270 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4271 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4272 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4274 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4275 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4276 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4278 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4279 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4280 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4281 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4283 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4284 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4285 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4286 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4287 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4288 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4289 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4290 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4292 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4293 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4294 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4296 g_free (mono_jit_stats.max_ratio_method);
4297 mono_jit_stats.max_ratio_method = NULL;
4298 g_free (mono_jit_stats.biggest_method);
4299 mono_jit_stats.biggest_method = NULL;
4304 mini_cleanup (MonoDomain *domain)
4306 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4307 mono_runtime_shutdown_stat_profiler ();
4310 cominterop_release_all_rcws ();
4313 #ifndef MONO_CROSS_COMPILE
4315 * mono_domain_finalize () needs to be called early since it needs the
4316 * execution engine still fully working (it may invoke managed finalizers).
4318 mono_domain_finalize (domain, 2000);
4321 /* This accesses metadata so needs to be called before runtime shutdown */
4324 #ifndef MONO_CROSS_COMPILE
4325 mono_runtime_cleanup (domain);
4328 mono_threadpool_cleanup ();
4330 mono_profiler_shutdown ();
4332 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4334 mono_icall_cleanup ();
4336 mono_runtime_cleanup_handlers ();
4338 #ifndef MONO_CROSS_COMPILE
4339 mono_domain_free (domain, TRUE);
4344 mono_llvm_cleanup ();
4347 mono_aot_cleanup ();
4349 mono_trampolines_cleanup ();
4351 mono_unwind_cleanup ();
4353 mono_code_manager_destroy (global_codeman);
4354 g_free (vtable_trampolines);
4356 mini_jit_cleanup ();
4358 mono_tramp_info_cleanup ();
4360 mono_arch_cleanup ();
4362 mono_generic_sharing_cleanup ();
4366 mono_trace_cleanup ();
4368 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4370 if (mono_inject_async_exc_method)
4371 mono_method_desc_free (mono_inject_async_exc_method);
4373 mono_tls_free_keys ();
4375 mono_os_mutex_destroy (&jit_mutex);
4377 mono_code_manager_cleanup ();
4380 mono_w32handle_cleanup ();
4385 mono_set_defaults (int verbose_level, guint32 opts)
4387 mini_verbose = verbose_level;
4388 mono_set_optimizations (opts);
4392 mono_disable_optimizations (guint32 opts)
4394 default_opt &= ~opts;
4398 mono_set_optimizations (guint32 opts)
4401 default_opt_set = TRUE;
4402 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4403 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4406 mono_set_generic_sharing_vt_supported (TRUE);
4411 mono_set_verbose_level (guint32 level)
4413 mini_verbose = level;
4417 * mono_get_runtime_build_info:
4418 * The returned string is owned by the caller. The returned string
4419 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4420 * \returns the runtime version + build date in string format.
4423 mono_get_runtime_build_info (void)
4425 if (mono_build_date)
4426 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4428 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4432 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4434 GHashTable *assemblies = (GHashTable*)user_data;
4435 MonoImage *image = mono_assembly_get_image (ass);
4436 MonoMethod *method, *invoke;
4439 if (g_hash_table_lookup (assemblies, ass))
4442 g_hash_table_insert (assemblies, ass, ass);
4444 if (mini_verbose > 0)
4445 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4447 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4450 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4452 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4455 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4457 if (method->is_generic || mono_class_is_gtd (method->klass))
4461 if (mini_verbose > 1) {
4462 char * desc = mono_method_full_name (method, TRUE);
4463 g_print ("Compiling %d %s\n", count, desc);
4466 mono_compile_method_checked (method, &error);
4467 if (!is_ok (&error)) {
4468 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4471 if (strcmp (method->name, "Finalize") == 0) {
4472 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4473 mono_compile_method_checked (invoke, &error);
4474 mono_error_assert_ok (&error);
4476 #ifndef DISABLE_REMOTING
4477 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4478 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4479 mono_compile_method_checked (invoke, &error);
4480 mono_error_assert_ok (&error);
4485 /* Load and precompile referenced assemblies as well */
4486 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4487 mono_assembly_load_reference (image, i);
4488 if (image->references [i])
4489 mono_precompile_assembly (image->references [i], assemblies);
4493 void mono_precompile_assemblies ()
4495 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4497 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4499 g_hash_table_destroy (assemblies);
4504 * Have to export this for AOT.
4507 mono_personality (void)
4510 g_assert_not_reached ();
4513 // Custom handlers currently only implemented by Windows.
4516 mono_runtime_install_custom_handlers (const char *handlers)
4522 mono_runtime_install_custom_handlers_usage (void)
4525 "Custom Handlers:\n"
4526 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4527 " separated list of available handlers to install.\n"
4529 "No handlers supported on current platform.\n");
4531 #endif /* HOST_WIN32 */