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 ();
488 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
490 copy = g_new0 (MonoTrampInfo, 1);
492 copy->code = info->code;
493 copy->code_size = info->code_size;
494 copy->name = g_strdup (info->name);
496 if (info->unwind_ops) {
497 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
498 copy->owns_uw_info = TRUE;
500 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
501 guint8 *temp = copy->uw_info;
502 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
503 memcpy (copy->uw_info, temp, copy->uw_info_len);
507 /* Trampolines from aot have the unwind ops already encoded */
508 copy->uw_info = info->uw_info;
509 copy->uw_info_len = info->uw_info_len;
512 mono_save_trampoline_xdebug_info (info);
513 mono_lldb_save_trampoline_info (info);
515 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
517 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
521 /* If no root domain has been created yet, postpone the registration. */
523 tramp_infos = g_slist_prepend (tramp_infos, copy);
525 } else if (copy->uw_info) {
526 /* Only register trampolines that have unwind infos */
527 register_trampoline_jit_info (domain, copy);
530 if (mono_jit_map_is_enabled ())
531 mono_emit_jit_tramp (info->code, info->code_size, info->name);
533 mono_tramp_info_free (info);
537 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
539 mono_tramp_info_register_internal (info, domain, FALSE);
543 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
545 mono_tramp_info_register_internal (info, domain, TRUE);
549 mono_tramp_info_cleanup (void)
553 for (l = tramp_infos; l; l = l->next) {
554 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
556 mono_tramp_info_free (info);
558 g_slist_free (tramp_infos);
561 /* Register trampolines created before the root domain was created in the jit info tables */
563 register_trampolines (MonoDomain *domain)
567 for (l = tramp_infos; l; l = l->next) {
568 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
570 register_trampoline_jit_info (domain, info);
574 G_GNUC_UNUSED static void
580 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
581 * Set a breakpoint in break_count () to break the last time <x> is done.
583 G_GNUC_UNUSED gboolean
584 mono_debug_count (void)
586 static int count = 0;
587 static gboolean inited;
593 value = g_getenv ("COUNT");
600 int int_val = atoi (value);
603 if (count == int_val)
613 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
618 gconstpointer trampoline;
619 MonoDomain *domain = mono_get_root_domain ();
620 gboolean check_exc = TRUE;
622 if (callinfo->wrapper)
623 return callinfo->wrapper;
625 if (callinfo->trampoline)
626 return callinfo->trampoline;
628 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
629 /* This icall is used to check for exceptions, so don't check in the wrapper */
632 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
633 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
637 trampoline = mono_compile_method_checked (wrapper, &error);
638 mono_error_assert_ok (&error);
641 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
642 mono_error_assert_ok (&error);
643 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
647 if (!callinfo->trampoline) {
648 mono_register_jit_icall_wrapper (callinfo, trampoline);
649 callinfo->trampoline = trampoline;
651 mono_loader_unlock ();
653 return callinfo->trampoline;
657 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
659 return mono_icall_get_wrapper_full (callinfo, FALSE);
662 static MonoJitDynamicMethodInfo*
663 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
665 MonoJitDynamicMethodInfo *res;
667 if (domain_jit_info (domain)->dynamic_code_hash)
668 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
675 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
678 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
680 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
682 g_assert (!sig->hasthis);
683 g_assert (sig->param_count < 3);
685 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
686 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
691 * For JIT icalls implemented in C.
692 * NAME should be the same as the name of the C function whose address is FUNC.
693 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
694 * can't throw exceptions.
697 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
699 MonoMethodSignature *sig;
702 sig = mono_create_icall_signature (sigstr);
706 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
710 register_icall_no_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, TRUE, FALSE, name);
723 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
725 MonoMethodSignature *sig;
728 sig = mono_create_icall_signature (sigstr);
732 mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
736 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
738 MonoMethodSignature *sig;
741 sig = mono_create_icall_signature (sigstr);
745 mono_register_jit_icall (func, name, sig, save);
751 MonoJitTlsData *jit_tls;
753 if ((jit_tls = mono_tls_get_jit_tls ()))
756 * We do not assert here because this function can be called from
757 * mini-gc.c on a thread that has not executed any managed code, yet
758 * (the thread object allocation can trigger a collection).
764 mono_get_lmf_addr (void)
766 return (MonoLMF **)mono_tls_get_lmf_addr ();
770 mono_set_lmf (MonoLMF *lmf)
772 (*mono_get_lmf_addr ()) = lmf;
776 mono_get_jit_tls (void)
778 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
782 mono_set_jit_tls (MonoJitTlsData *jit_tls)
784 MonoThreadInfo *info;
786 mono_tls_set_jit_tls (jit_tls);
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_JIT_TLS, jit_tls);
795 mono_set_lmf_addr (gpointer lmf_addr)
797 MonoThreadInfo *info;
799 mono_tls_set_lmf_addr (lmf_addr);
801 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
802 info = mono_thread_info_current ();
804 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
810 * Push an MonoLMFExt frame on the LMF stack.
813 mono_push_lmf (MonoLMFExt *ext)
815 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
818 lmf_addr = mono_get_lmf_addr ();
820 mono_arch_init_lmf_ext (ext, *lmf_addr);
822 mono_set_lmf ((MonoLMF*)ext);
831 * Pop the last frame from the LMF stack.
834 mono_pop_lmf (MonoLMF *lmf)
836 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
840 * mono_jit_thread_attach:
842 * Called by Xamarin.Mac and other products. Attach thread to runtime if
843 * needed and switch to @domain.
845 * @return the original domain which needs to be restored, or NULL.
848 mono_jit_thread_attach (MonoDomain *domain)
853 g_assert (!mono_threads_is_coop_enabled ());
856 /* Happens when called from AOTed code which is only used in the root domain. */
857 domain = mono_get_root_domain ();
862 attached = mono_tls_get_jit_tls () != NULL;
865 mono_thread_attach (domain);
868 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
871 orig = mono_domain_get ();
873 mono_domain_set (domain, TRUE);
875 return orig != domain ? orig : NULL;
879 * mono_jit_set_domain:
881 * Set domain to @domain if @domain is not null
884 mono_jit_set_domain (MonoDomain *domain)
886 g_assert (!mono_threads_is_coop_enabled ());
889 mono_domain_set (domain, TRUE);
894 * \param obj exception object
895 * Abort the thread, print exception information and stack trace
898 mono_thread_abort (MonoObject *obj)
900 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
902 /* handle_remove should be eventually called for this thread, too
905 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
906 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
909 mono_invoke_unhandled_exception_hook (obj);
914 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
916 MonoJitTlsData *jit_tls;
919 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
923 jit_tls = g_new0 (MonoJitTlsData, 1);
925 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
926 jit_tls->end_of_stack = stack_start;
928 mono_set_jit_tls (jit_tls);
930 lmf = g_new0 (MonoLMF, 1);
931 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
933 jit_tls->first_lmf = lmf;
935 mono_set_lmf_addr (&jit_tls->lmf);
939 #ifdef MONO_ARCH_HAVE_TLS_INIT
940 mono_arch_tls_init ();
943 mono_setup_altstack (jit_tls);
949 free_jit_tls_data (MonoJitTlsData *jit_tls)
951 mono_arch_free_jit_tls_data (jit_tls);
952 mono_free_altstack (jit_tls);
954 g_free (jit_tls->first_lmf);
959 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
961 MonoThreadInfo *thread;
962 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
963 thread = mono_thread_info_current_unchecked ();
965 thread->jit_data = jit_tls;
967 mono_arch_cpu_init ();
970 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
973 mono_thread_abort_dummy (MonoObject *obj)
975 if (mono_thread_attach_aborted_cb)
976 mono_thread_attach_aborted_cb (obj);
978 mono_thread_abort (obj);
982 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
984 MonoThreadInfo *thread;
985 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
986 thread = mono_thread_info_current_unchecked ();
988 thread->jit_data = jit_tls;
990 mono_arch_cpu_init ();
994 mini_thread_cleanup (MonoNativeThreadId tid)
996 MonoJitTlsData *jit_tls = NULL;
997 MonoThreadInfo *info;
999 info = mono_thread_info_current_unchecked ();
1001 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1002 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1003 * not a trivial thing.
1005 * The current offender is mono_thread_manage which cleanup threads from the outside.
1007 if (info && mono_thread_info_get_tid (info) == tid) {
1008 jit_tls = (MonoJitTlsData *)info->jit_data;
1009 info->jit_data = NULL;
1011 mono_set_jit_tls (NULL);
1013 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1014 if (mono_get_lmf ()) {
1015 mono_set_lmf (NULL);
1016 mono_set_lmf_addr (NULL);
1019 info = mono_thread_info_lookup (tid);
1021 jit_tls = (MonoJitTlsData *)info->jit_data;
1022 info->jit_data = NULL;
1024 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1028 free_jit_tls_data (jit_tls);
1032 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1034 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1038 ji->data.target = target;
1044 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1046 static const char* const patch_info_str[] = {
1047 #define PATCH_INFO(a,b) "" #a,
1048 #include "patch-info.h"
1053 mono_ji_type_to_string (MonoJumpInfoType type)
1055 return patch_info_str [type];
1059 mono_print_ji (const MonoJumpInfo *ji)
1062 case MONO_PATCH_INFO_RGCTX_FETCH: {
1063 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1065 printf ("[RGCTX_FETCH ");
1066 mono_print_ji (entry->data);
1067 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1070 case MONO_PATCH_INFO_METHODCONST: {
1071 char *s = mono_method_full_name (ji->data.method, TRUE);
1072 printf ("[METHODCONST - %s]", s);
1076 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1077 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1081 printf ("[%s]", patch_info_str [ji->type]);
1089 mono_ji_type_to_string (MonoJumpInfoType type)
1095 mono_print_ji (const MonoJumpInfo *ji)
1102 * mono_patch_info_dup_mp:
1104 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1107 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1109 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1110 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1112 switch (patch_info->type) {
1113 case MONO_PATCH_INFO_RVA:
1114 case MONO_PATCH_INFO_LDSTR:
1115 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1116 case MONO_PATCH_INFO_LDTOKEN:
1117 case MONO_PATCH_INFO_DECLSEC:
1118 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1119 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1121 case MONO_PATCH_INFO_SWITCH:
1122 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1123 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1124 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1125 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1127 case MONO_PATCH_INFO_RGCTX_FETCH:
1128 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1129 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1130 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1131 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1133 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1134 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1135 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1137 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1138 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1139 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1141 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1142 MonoGSharedVtMethodInfo *info;
1143 MonoGSharedVtMethodInfo *oinfo;
1146 oinfo = patch_info->data.gsharedvt_method;
1147 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1148 res->data.gsharedvt_method = info;
1149 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1150 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1151 for (i = 0; i < oinfo->num_entries; ++i) {
1152 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1153 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1155 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1157 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1158 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1161 case MONO_PATCH_INFO_VIRT_METHOD: {
1162 MonoJumpInfoVirtMethod *info;
1163 MonoJumpInfoVirtMethod *oinfo;
1165 oinfo = patch_info->data.virt_method;
1166 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1167 res->data.virt_method = info;
1168 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1179 mono_patch_info_hash (gconstpointer data)
1181 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1184 case MONO_PATCH_INFO_RVA:
1185 case MONO_PATCH_INFO_LDSTR:
1186 case MONO_PATCH_INFO_LDTOKEN:
1187 case MONO_PATCH_INFO_DECLSEC:
1188 return (ji->type << 8) | ji->data.token->token;
1189 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1190 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1191 case MONO_PATCH_INFO_INTERNAL_METHOD:
1192 return (ji->type << 8) | g_str_hash (ji->data.name);
1193 case MONO_PATCH_INFO_VTABLE:
1194 case MONO_PATCH_INFO_CLASS:
1195 case MONO_PATCH_INFO_IID:
1196 case MONO_PATCH_INFO_ADJUSTED_IID:
1197 case MONO_PATCH_INFO_METHODCONST:
1198 case MONO_PATCH_INFO_METHOD:
1199 case MONO_PATCH_INFO_METHOD_JUMP:
1200 case MONO_PATCH_INFO_IMAGE:
1201 case MONO_PATCH_INFO_ICALL_ADDR:
1202 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1203 case MONO_PATCH_INFO_FIELD:
1204 case MONO_PATCH_INFO_SFLDA:
1205 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1206 case MONO_PATCH_INFO_METHOD_RGCTX:
1207 case MONO_PATCH_INFO_SIGNATURE:
1208 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1209 case MONO_PATCH_INFO_AOT_JIT_INFO:
1210 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1211 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1212 return (ji->type << 8) | (gssize)ji->data.target;
1213 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1214 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1215 case MONO_PATCH_INFO_RGCTX_FETCH:
1216 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1217 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1219 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1221 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1222 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1223 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1224 case MONO_PATCH_INFO_GC_NURSERY_START:
1225 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1226 case MONO_PATCH_INFO_GOT_OFFSET:
1227 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1228 case MONO_PATCH_INFO_AOT_MODULE:
1229 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1230 return (ji->type << 8);
1231 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1232 return (ji->type << 8) | (ji->data.index);
1233 case MONO_PATCH_INFO_SWITCH:
1234 return (ji->type << 8) | ji->data.table->table_size;
1235 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1236 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1237 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1238 /* Hash on the selector name */
1239 return g_str_hash (ji->data.target);
1240 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1241 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1242 case MONO_PATCH_INFO_LDSTR_LIT:
1243 return g_str_hash (ji->data.target);
1244 case MONO_PATCH_INFO_VIRT_METHOD: {
1245 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1247 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1249 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1250 return (ji->type << 8) | g_str_hash (ji->data.target);
1251 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1252 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1254 printf ("info type: %d\n", ji->type);
1255 mono_print_ji (ji); printf ("\n");
1256 g_assert_not_reached ();
1262 * mono_patch_info_equal:
1264 * This might fail to recognize equivalent patches, i.e. floats, so its only
1265 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1269 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1271 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1272 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1274 if (ji1->type != ji2->type)
1277 switch (ji1->type) {
1278 case MONO_PATCH_INFO_RVA:
1279 case MONO_PATCH_INFO_LDSTR:
1280 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1281 case MONO_PATCH_INFO_LDTOKEN:
1282 case MONO_PATCH_INFO_DECLSEC:
1283 if ((ji1->data.token->image != ji2->data.token->image) ||
1284 (ji1->data.token->token != ji2->data.token->token) ||
1285 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1286 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1287 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1290 case MONO_PATCH_INFO_INTERNAL_METHOD:
1291 return g_str_equal (ji1->data.name, ji2->data.name);
1292 case MONO_PATCH_INFO_RGCTX_FETCH:
1293 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1294 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1295 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1297 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);
1299 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1300 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1301 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1303 return c1->sig == c2->sig && c1->method == c2->method;
1305 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1306 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1307 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1308 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;
1309 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1310 return ji1->data.index == ji2->data.index;
1311 case MONO_PATCH_INFO_VIRT_METHOD:
1312 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1313 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1314 if (ji1->data.target == ji2->data.target)
1316 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1317 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1318 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1320 if (ji1->data.target != ji2->data.target)
1329 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1331 unsigned char *ip = patch_info->ip.i + code;
1332 gconstpointer target = NULL;
1336 switch (patch_info->type) {
1337 case MONO_PATCH_INFO_BB:
1339 * FIXME: This could be hit for methods without a prolog. Should use -1
1340 * but too much code depends on a 0 initial value.
1342 //g_assert (patch_info->data.bb->native_offset);
1343 target = patch_info->data.bb->native_offset + code;
1345 case MONO_PATCH_INFO_ABS:
1346 target = patch_info->data.target;
1348 case MONO_PATCH_INFO_LABEL:
1349 target = patch_info->data.inst->inst_c0 + code;
1351 case MONO_PATCH_INFO_IP:
1354 case MONO_PATCH_INFO_METHOD_REL:
1355 target = code + patch_info->data.offset;
1357 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1358 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1360 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1361 g_assert_not_reached ();
1363 target = mono_icall_get_wrapper (mi);
1366 case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
1367 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1369 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1370 g_assert_not_reached ();
1375 case MONO_PATCH_INFO_METHOD_JUMP:
1376 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1377 if (!mono_error_ok (error))
1380 case MONO_PATCH_INFO_METHOD:
1381 if (patch_info->data.method == method) {
1384 /* get the trampoline to the method from the domain */
1385 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1386 if (!mono_error_ok (error))
1390 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1393 mono_domain_lock (domain);
1394 if (!domain_jit_info (domain)->method_code_hash)
1395 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1396 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1398 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1399 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1401 mono_domain_unlock (domain);
1405 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1406 #if defined(__native_client_codegen__)
1407 target = (gpointer)&__nacl_thread_suspension_needed;
1409 g_assert (mono_threads_is_coop_enabled ());
1410 target = (gpointer)&mono_polling_required;
1413 case MONO_PATCH_INFO_SWITCH: {
1414 gpointer *jump_table;
1416 #if defined(__native_client__) && defined(__native_client_codegen__)
1417 /* This memory will leak, but we don't care if we're */
1418 /* not deleting JIT'd methods anyway */
1419 jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
1421 if (method && method->dynamic) {
1422 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1424 if (mono_aot_only) {
1425 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1427 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1432 for (i = 0; i < patch_info->data.table->table_size; i++) {
1433 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1436 target = jump_table;
1439 case MONO_PATCH_INFO_METHODCONST:
1440 case MONO_PATCH_INFO_CLASS:
1441 case MONO_PATCH_INFO_IMAGE:
1442 case MONO_PATCH_INFO_FIELD:
1443 case MONO_PATCH_INFO_SIGNATURE:
1444 case MONO_PATCH_INFO_AOT_MODULE:
1445 target = patch_info->data.target;
1447 case MONO_PATCH_INFO_IID:
1448 mono_class_init (patch_info->data.klass);
1449 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1451 case MONO_PATCH_INFO_ADJUSTED_IID:
1452 mono_class_init (patch_info->data.klass);
1453 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1455 case MONO_PATCH_INFO_VTABLE:
1456 target = mono_class_vtable (domain, patch_info->data.klass);
1459 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1460 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1462 if (del_tramp->is_virtual)
1463 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1465 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1468 case MONO_PATCH_INFO_SFLDA: {
1469 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1471 if (mono_class_field_is_special_static (patch_info->data.field)) {
1472 gpointer addr = NULL;
1474 mono_domain_lock (domain);
1475 if (domain->special_static_fields)
1476 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1477 mono_domain_unlock (domain);
1483 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1484 /* Done by the generated code */
1488 if (!mono_runtime_class_init_full (vtable, error)) {
1493 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1496 case MONO_PATCH_INFO_RVA: {
1497 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1500 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1501 target = mono_image_rva_map (patch_info->data.token->image, rva);
1504 case MONO_PATCH_INFO_R4:
1505 case MONO_PATCH_INFO_R8:
1506 target = patch_info->data.target;
1508 case MONO_PATCH_INFO_EXC_NAME:
1509 target = patch_info->data.name;
1511 case MONO_PATCH_INFO_LDSTR:
1513 mono_ldstr_checked (domain, patch_info->data.token->image,
1514 mono_metadata_token_index (patch_info->data.token->token), error);
1516 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1518 MonoClass *handle_class;
1520 handle = mono_ldtoken_checked (patch_info->data.token->image,
1521 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1522 if (!mono_error_ok (error))
1524 mono_class_init (handle_class);
1525 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1527 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1528 if (!mono_error_ok (error))
1532 case MONO_PATCH_INFO_LDTOKEN: {
1534 MonoClass *handle_class;
1536 handle = mono_ldtoken_checked (patch_info->data.token->image,
1537 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1538 if (!mono_error_ok (error))
1539 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1540 mono_class_init (handle_class);
1545 case MONO_PATCH_INFO_DECLSEC:
1546 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1548 case MONO_PATCH_INFO_ICALL_ADDR:
1549 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1550 /* run_cctors == 0 -> AOT */
1551 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1552 const char *exc_class;
1553 const char *exc_arg;
1556 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1558 if (mono_aot_only) {
1559 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1562 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));
1568 target = mono_lookup_internal_call (patch_info->data.method);
1570 if (!target && run_cctors)
1571 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1574 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1575 target = mono_thread_interruption_request_flag ();
1577 case MONO_PATCH_INFO_METHOD_RGCTX: {
1578 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1581 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1584 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1585 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1587 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1590 case MONO_PATCH_INFO_BB_OVF:
1591 case MONO_PATCH_INFO_EXC_OVF:
1592 case MONO_PATCH_INFO_GOT_OFFSET:
1593 case MONO_PATCH_INFO_NONE:
1595 case MONO_PATCH_INFO_RGCTX_FETCH: {
1596 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1598 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1601 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1602 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1604 /* AOT, not needed */
1607 target = mono_arch_get_seq_point_info (domain, code);
1610 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1611 int card_table_shift_bits;
1612 gpointer card_table_mask;
1614 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1617 case MONO_PATCH_INFO_GC_NURSERY_START: {
1621 target = mono_gc_get_nursery (&shift_bits, &size);
1624 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1628 mono_gc_get_nursery (&shift_bits, &size);
1630 target = (gpointer)(mgreg_t)shift_bits;
1633 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1634 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1637 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1641 case MONO_PATCH_INFO_LDSTR_LIT: {
1645 len = strlen ((const char *)patch_info->data.target);
1646 s = (char *)mono_domain_alloc0 (domain, len + 1);
1647 memcpy (s, patch_info->data.target, len);
1652 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1653 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1655 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1656 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1658 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1659 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1661 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1662 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1668 g_assert_not_reached ();
1671 return (gpointer)target;
1675 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1677 MonoGenericInst *inst;
1680 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1682 if (context && context->class_inst) {
1683 inst = context->class_inst;
1684 for (i = 0; i < inst->type_argc; ++i) {
1685 MonoType *type = inst->type_argv [i];
1687 if (mini_is_gsharedvt_gparam (type))
1688 gsctx->is_gsharedvt = TRUE;
1691 if (context && context->method_inst) {
1692 inst = context->method_inst;
1694 for (i = 0; i < inst->type_argc; ++i) {
1695 MonoType *type = inst->type_argv [i];
1697 if (mini_is_gsharedvt_gparam (type))
1698 gsctx->is_gsharedvt = TRUE;
1704 * LOCKING: Acquires the jit code hash lock.
1707 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1710 static gboolean inited = FALSE;
1711 static int lookups = 0;
1712 static int failed_lookups = 0;
1714 mono_domain_jit_code_hash_lock (domain);
1715 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1716 if (!ji && shared) {
1717 /* Try generic sharing */
1718 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1719 if (ji && !ji->has_generic_jit_info)
1722 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1723 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1731 mono_domain_jit_code_hash_unlock (domain);
1737 lookup_method (MonoDomain *domain, MonoMethod *method)
1742 ji = mini_lookup_method (domain, method, NULL);
1745 if (!mono_method_is_generic_sharable (method, FALSE))
1747 shared = mini_get_shared_method (method);
1748 ji = mini_lookup_method (domain, method, shared);
1755 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1757 return lookup_method (domain, method);
1761 static FILE* perf_map_file;
1764 mono_enable_jit_map (void)
1766 if (!perf_map_file) {
1768 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1770 perf_map_file = fopen (name, "w");
1775 mono_emit_jit_tramp (void *start, int size, const char *desc)
1778 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1782 mono_emit_jit_map (MonoJitInfo *jinfo)
1784 if (perf_map_file) {
1785 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1786 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1792 mono_jit_map_is_enabled (void)
1794 return perf_map_file != NULL;
1800 no_gsharedvt_in_wrapper (void)
1802 g_assert_not_reached ();
1808 When a JIT request is made, we check if there's an outstanding one for that method and, if it exits, put the thread to sleep.
1809 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1810 Dependency management in this case is too complex to justify implementing it.
1812 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1815 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1816 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1817 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1818 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1823 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1824 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1825 int threads_waiting; /* Number of threads waiting on this job */
1826 gboolean has_cond; /* True if @cond was initialized */
1827 gboolean done; /* True if the method finished JIT'ing */
1828 MonoCoopCond cond; /* Cond sleeping threads wait one */
1829 } JitCompilationEntry;
1832 GPtrArray *in_flight_methods; //JitCompilationEntry*
1834 } JitCompilationData;
1836 static JitCompilationData compilation_data;
1837 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1840 mini_jit_init_job_control (void)
1842 mono_coop_mutex_init (&compilation_data.lock);
1843 compilation_data.in_flight_methods = g_ptr_array_new ();
1847 lock_compilation_data (void)
1849 mono_coop_mutex_lock (&compilation_data.lock);
1853 unlock_compilation_data (void)
1855 mono_coop_mutex_unlock (&compilation_data.lock);
1858 static JitCompilationEntry*
1859 find_method (MonoMethod *method, MonoDomain *domain)
1862 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1863 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1864 if (e->method == method && e->domain == domain)
1872 add_current_thread (MonoJitTlsData *jit_tls)
1874 ++jit_tls->active_jit_methods;
1878 unref_jit_entry (JitCompilationEntry *entry)
1881 if (entry->ref_count)
1883 if (entry->has_cond)
1884 mono_coop_cond_destroy (&entry->cond);
1889 * Returns true if this method waited successfully for another thread to JIT it
1892 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1894 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1895 JitCompilationEntry *entry;
1897 static gboolean inited;
1899 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1900 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1901 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1902 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1906 lock_compilation_data ();
1908 if (!(entry = find_method (method, domain))) {
1909 entry = g_new0 (JitCompilationEntry, 1);
1910 entry->method = method;
1911 entry->domain = domain;
1912 entry->compilation_count = entry->ref_count = 1;
1913 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1914 g_assert (find_method (method, domain) == entry);
1915 add_current_thread (jit_tls);
1917 unlock_compilation_data ();
1919 } else if (jit_tls->active_jit_methods > 0) {
1920 //We can't suspend the current thread if it's already JITing a method.
1921 //Dependency management is too compilated and we want to get rid of this anyways.
1922 ++entry->compilation_count;
1923 ++jit_methods_multiple;
1924 ++jit_tls->active_jit_methods;
1926 unlock_compilation_data ();
1929 ++jit_methods_waited;
1932 if (!entry->has_cond) {
1933 mono_coop_cond_init (&entry->cond);
1934 entry->has_cond = TRUE;
1938 ++entry->threads_waiting;
1940 g_assert (entry->has_cond);
1941 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1942 --entry->threads_waiting;
1945 unref_jit_entry (entry);
1946 unlock_compilation_data ();
1949 ++jit_spurious_wakeups;
1956 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1958 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1960 lock_compilation_data ();
1962 g_assert (jit_tls->active_jit_methods > 0);
1963 --jit_tls->active_jit_methods;
1965 JitCompilationEntry *entry = find_method (method, target_domain);
1966 g_assert (entry); // It would be weird to fail
1969 if (entry->threads_waiting) {
1970 g_assert (entry->has_cond);
1971 mono_coop_cond_broadcast (&entry->cond);
1974 if (--entry->compilation_count == 0) {
1975 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1976 unref_jit_entry (entry);
1979 unlock_compilation_data ();
1984 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1986 MonoDomain *target_domain, *domain = mono_domain_get ();
1988 gpointer code = NULL, p;
1990 MonoJitICallInfo *callinfo = NULL;
1991 WrapperInfo *winfo = NULL;
1995 #ifdef ENABLE_INTERPRETER
1996 if (mono_use_interpreter && !jit_only) {
1997 code = mono_interp_create_method_pointer (method, error);
2004 /* Should be handled by the caller */
2005 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2008 * ICALL wrappers are handled specially, since there is only one copy of them
2009 * shared by all appdomains.
2011 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2012 winfo = mono_marshal_get_wrapper_info (method);
2013 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2014 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2015 g_assert (callinfo);
2017 /* Must be domain neutral since there is only one copy */
2018 opt |= MONO_OPT_SHARED;
2020 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2021 opt &= ~MONO_OPT_SHARED;
2024 if (opt & MONO_OPT_SHARED)
2025 target_domain = mono_get_root_domain ();
2027 target_domain = domain;
2029 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2030 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2033 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2034 MonoGenericContext *ctx = NULL;
2035 if (method->is_inflated)
2036 ctx = mono_method_get_context (method);
2037 method = info->d.synchronized_inner.method;
2039 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2040 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2046 info = lookup_method (target_domain, method);
2048 /* We can't use a domain specific method in another domain */
2049 if (! ((domain != target_domain) && !info->domain_neutral)) {
2052 mono_jit_stats.methods_lookups++;
2053 vtable = mono_class_vtable_full (domain, method->klass, error);
2057 if (!mono_runtime_class_init_full (vtable, error))
2059 return mono_create_ftnptr (target_domain, info->code_start);
2063 #ifdef MONO_USE_AOT_COMPILER
2064 if (opt & MONO_OPT_AOT) {
2065 MonoDomain *domain = mono_domain_get ();
2067 mono_class_init (method->klass);
2069 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2072 if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
2074 * The suspend code needs to be able to lookup these methods by ip in async context,
2075 * so preload their jit info.
2077 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2082 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2083 * This is not a problem, since it will be initialized when the method is first
2084 * called by init_method ().
2086 if (!mono_llvm_only) {
2087 vtable = mono_class_vtable (domain, method->klass);
2089 if (!mono_runtime_class_init_full (vtable, error))
2098 if (!code && mono_llvm_only) {
2099 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2100 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2102 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2104 * These wrappers are only created for signatures which are in the program, but
2105 * sometimes we load methods too eagerly and have to create them even if they
2106 * will never be called.
2108 return no_gsharedvt_in_wrapper;
2114 if (wait_or_register_method_to_compile (method, target_domain))
2116 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2117 unregister_method_for_compile (method, target_domain);
2119 if (!mono_error_ok (error))
2122 if (!code && mono_llvm_only) {
2123 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2124 g_assert_not_reached ();
2130 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2134 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2136 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2140 p = mono_create_ftnptr (target_domain, code);
2143 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2144 mono_loader_lock ();
2146 if (!callinfo->wrapper) {
2147 callinfo->wrapper = p;
2148 mono_register_jit_icall_wrapper (callinfo, p);
2151 mono_loader_unlock ();
2158 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2162 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2167 * mono_jit_compile_method_jit_only:
2169 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2172 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2176 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2180 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2182 invalidated_delegate_trampoline (char *desc)
2184 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2185 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2191 * mono_jit_free_method:
2193 * Free all memory allocated by the JIT for METHOD.
2196 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2198 MonoJitDynamicMethodInfo *ji;
2199 gboolean destroy = TRUE;
2200 GHashTableIter iter;
2201 MonoJumpList *jlist;
2203 g_assert (method->dynamic);
2205 mono_domain_lock (domain);
2206 ji = mono_dynamic_code_hash_lookup (domain, method);
2207 mono_domain_unlock (domain);
2212 mono_debug_remove_method (method, domain);
2213 mono_lldb_remove_method (domain, method, ji);
2215 mono_domain_lock (domain);
2216 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2217 mono_domain_jit_code_hash_lock (domain);
2218 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2219 mono_domain_jit_code_hash_unlock (domain);
2220 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2222 /* requires the domain lock - took above */
2223 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2225 /* Remove jump targets in this method */
2226 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2227 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2228 GSList *tmp, *remove;
2231 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2232 guint8 *ip = (guint8 *)tmp->data;
2234 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2235 remove = g_slist_prepend (remove, tmp);
2237 for (tmp = remove; tmp; tmp = tmp->next) {
2238 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2240 g_slist_free (remove);
2242 mono_domain_unlock (domain);
2244 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2245 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2247 * Instead of freeing the code, change it to call an error routine
2248 * so people can fix their code.
2250 char *type = mono_type_full_name (&method->klass->byval_arg);
2251 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2254 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2260 * This needs to be done before freeing code_mp, since the code address is the
2261 * key in the table, so if we free the code_mp first, another thread can grab the
2262 * same code address and replace our entry in the table.
2264 mono_jit_info_table_remove (domain, ji->ji);
2267 mono_code_manager_destroy (ji->code_mp);
2272 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2274 MonoDomain *target_domain;
2277 if (default_opt & MONO_OPT_SHARED)
2278 target_domain = mono_get_root_domain ();
2280 target_domain = domain;
2282 info = lookup_method (target_domain, method);
2284 /* We can't use a domain specific method in another domain */
2285 if (! ((domain != target_domain) && !info->domain_neutral)) {
2286 mono_jit_stats.methods_lookups++;
2289 return info->code_start;
2298 static guint32 bisect_opt = 0;
2299 static GHashTable *bisect_methods_hash = NULL;
2302 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2305 char method_name [2048];
2308 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2309 g_assert (bisect_methods_hash);
2311 file = fopen (method_list_filename, "r");
2314 while (fgets (method_name, sizeof (method_name), file)) {
2315 size_t len = strlen (method_name);
2317 g_assert (method_name [len - 1] == '\n');
2318 method_name [len - 1] = 0;
2319 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2321 g_assert (feof (file));
2324 gboolean mono_do_single_method_regression = FALSE;
2325 guint32 mono_single_method_regression_opt = 0;
2326 MonoMethod *mono_current_single_method;
2327 GSList *mono_single_method_list;
2328 GHashTable *mono_single_method_hash;
2331 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2335 if (bisect_methods_hash) {
2336 char *name = mono_method_full_name (method, TRUE);
2337 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2340 return default_opt | bisect_opt;
2342 if (!mono_do_single_method_regression)
2344 if (!mono_current_single_method) {
2345 if (!mono_single_method_hash)
2346 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2347 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2348 g_hash_table_insert (mono_single_method_hash, method, method);
2349 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2353 if (method == mono_current_single_method)
2354 return mono_single_method_regression_opt;
2359 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2361 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2366 gpointer compiled_method;
2367 gpointer runtime_invoke;
2369 MonoDynCallInfo *dyn_call_info;
2370 MonoClass *ret_box_class;
2371 MonoMethodSignature *sig;
2372 gboolean gsharedvt_invoke;
2373 gpointer *wrapper_arg;
2374 } RuntimeInvokeInfo;
2376 static RuntimeInvokeInfo*
2377 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2380 RuntimeInvokeInfo *info;
2382 info = g_new0 (RuntimeInvokeInfo, 1);
2383 info->compiled_method = compiled_method;
2384 if (mono_llvm_only && method->string_ctor)
2385 info->sig = mono_marshal_get_string_ctor_signature (method);
2387 info->sig = mono_method_signature (method);
2389 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2390 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2391 if (!mono_error_ok (error))
2393 g_assert (info->vtable);
2395 MonoMethodSignature *sig = info->sig;
2399 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2400 * in full-aot mode, so we use a slower, but more generic wrapper if
2401 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2403 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2404 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2405 gboolean supported = TRUE;
2408 if (method->string_ctor)
2409 sig = mono_marshal_get_string_ctor_signature (method);
2411 for (i = 0; i < sig->param_count; ++i) {
2412 MonoType *t = sig->params [i];
2414 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2418 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2422 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2426 ret_type = sig->ret;
2427 switch (ret_type->type) {
2428 case MONO_TYPE_VOID:
2440 case MONO_TYPE_BOOLEAN:
2441 case MONO_TYPE_CHAR:
2444 info->ret_box_class = mono_class_from_mono_type (ret_type);
2447 info->ret_box_class = mono_defaults.int_class;
2449 case MONO_TYPE_STRING:
2450 case MONO_TYPE_CLASS:
2451 case MONO_TYPE_ARRAY:
2452 case MONO_TYPE_SZARRAY:
2453 case MONO_TYPE_OBJECT:
2455 case MONO_TYPE_GENERICINST:
2456 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2457 info->ret_box_class = mono_class_from_mono_type (ret_type);
2459 case MONO_TYPE_VALUETYPE:
2460 info->ret_box_class = mono_class_from_mono_type (ret_type);
2463 g_assert_not_reached ();
2467 if (!info->dyn_call_info) {
2468 if (mono_llvm_only) {
2469 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2470 g_assert_not_reached ();
2472 info->gsharedvt_invoke = TRUE;
2473 if (!callee_gsharedvt) {
2474 /* Invoke a gsharedvt out wrapper instead */
2475 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2476 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2478 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2479 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2481 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2482 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2483 g_free (wrapper_sig);
2485 info->compiled_method = mono_jit_compile_method (wrapper, error);
2486 if (!mono_error_ok (error)) {
2491 /* Gsharedvt methods can be invoked the same way */
2492 /* The out wrapper has the same signature as the compiled gsharedvt method */
2493 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2495 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2497 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2498 g_free (wrapper_sig);
2501 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2502 if (!mono_error_ok (error)) {
2512 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2514 MonoMethodSignature *sig = info->sig;
2515 MonoDomain *domain = mono_domain_get ();
2516 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2518 gpointer retval_ptr;
2519 guint8 retval [256];
2520 gpointer *param_refs;
2525 g_assert (info->gsharedvt_invoke);
2528 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2529 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2530 * signatures, so we only have to generate runtime invoke wrappers for these
2532 * This code also handles invocation of gsharedvt methods directly, no
2533 * out wrappers are used in that case.
2535 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2536 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2539 * The runtime invoke wrappers expects pointers to primitive types, so have to
2543 args [pindex ++] = &obj;
2544 if (sig->ret->type != MONO_TYPE_VOID) {
2545 retval_ptr = (gpointer)&retval;
2546 args [pindex ++] = &retval_ptr;
2548 for (i = 0; i < sig->param_count; ++i) {
2549 MonoType *t = sig->params [i];
2551 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2552 MonoClass *klass = mono_class_from_mono_type (t);
2553 guint8 *nullable_buf;
2556 size = mono_class_value_size (klass, NULL);
2557 nullable_buf = g_alloca (size);
2558 g_assert (nullable_buf);
2560 /* The argument pointed to by params [i] is either a boxed vtype or null */
2561 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2562 params [i] = nullable_buf;
2565 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2566 param_refs [i] = params [i];
2567 params [i] = &(param_refs [i]);
2569 args [pindex ++] = ¶ms [i];
2571 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2572 args [pindex ++] = &info->wrapper_arg;
2574 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2576 runtime_invoke (NULL, args, exc, info->compiled_method);
2580 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2581 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2583 return *(MonoObject**)retval;
2587 * mono_jit_runtime_invoke:
2588 * \param method: the method to invoke
2589 * \param obj: this pointer
2590 * \param params: array of parameter values.
2591 * \param exc: Set to the exception raised in the managed method.
2592 * \param error: error or caught exception object
2593 * If \p exc is NULL, \p error is thrown instead.
2594 * If coop is enabled, \p exc argument is ignored -
2595 * all exceptions are caught and propagated through \p error
2598 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2600 MonoMethod *invoke, *callee;
2601 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2602 MonoDomain *domain = mono_domain_get ();
2603 MonoJitDomainInfo *domain_info;
2604 RuntimeInvokeInfo *info, *info2;
2605 MonoJitInfo *ji = NULL;
2606 gboolean callee_gsharedvt = FALSE;
2608 #ifdef ENABLE_INTERPRETER
2609 if (mono_use_interpreter)
2610 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2615 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2616 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2620 domain_info = domain_jit_info (domain);
2622 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2625 if (mono_security_core_clr_enabled ()) {
2627 * This might be redundant since mono_class_vtable () already does this,
2628 * but keep it just in case for moonlight.
2630 mono_class_setup_vtable (method->klass);
2631 if (mono_class_has_failure (method->klass)) {
2632 mono_error_set_for_class_failure (error, method->klass);
2634 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2639 gpointer compiled_method;
2642 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2643 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2645 * Array Get/Set/Address methods. The JIT implements them using inline code
2646 * inside the runtime invoke wrappers, so no need to compile them.
2648 if (mono_aot_only) {
2650 * Call a wrapper, since the runtime invoke wrapper was not generated.
2652 MonoMethod *wrapper;
2654 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2655 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2663 compiled_method = mono_jit_compile_method (callee, error);
2664 if (!compiled_method) {
2665 g_assert (!mono_error_ok (error));
2669 if (mono_llvm_only) {
2670 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2671 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2672 if (callee_gsharedvt)
2673 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2676 if (!callee_gsharedvt)
2677 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2679 compiled_method = NULL;
2682 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2683 if (!mono_error_ok (error))
2686 mono_domain_lock (domain);
2687 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2688 mono_domain_unlock (domain);
2696 * We need this here because mono_marshal_get_runtime_invoke can place
2697 * the helper method in System.Object and not the target class.
2699 if (!mono_runtime_class_init_full (info->vtable, error)) {
2701 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2705 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2706 we always catch the exception and propagate it through the MonoError */
2707 gboolean catchExcInMonoError =
2708 (exc == NULL) && mono_threads_is_coop_enabled ();
2709 MonoObject *invoke_exc = NULL;
2710 if (catchExcInMonoError)
2713 /* The wrappers expect this to be initialized to NULL */
2717 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2718 if (info->dyn_call_info) {
2719 MonoMethodSignature *sig = mono_method_signature (method);
2721 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2724 guint8 retval [256];
2726 if (!dyn_runtime_invoke) {
2727 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2728 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2729 if (!mono_error_ok (error))
2733 /* Convert the arguments to the format expected by start_dyn_call () */
2734 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2737 args [pindex ++] = &obj;
2738 for (i = 0; i < sig->param_count; ++i) {
2739 MonoType *t = sig->params [i];
2742 args [pindex ++] = ¶ms [i];
2743 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2744 args [pindex ++] = ¶ms [i];
2746 args [pindex ++] = params [i];
2750 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2752 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2754 dyn_runtime_invoke (buf, exc, info->compiled_method);
2755 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2757 if (catchExcInMonoError && *exc != NULL) {
2758 mono_error_set_exception_instance (error, (MonoException*) *exc);
2762 if (info->ret_box_class)
2763 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2765 return *(MonoObject**)retval;
2771 if (mono_llvm_only) {
2772 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2776 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2778 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2780 if (catchExcInMonoError && *exc != NULL)
2781 mono_error_set_exception_instance (error, (MonoException*) *exc);
2790 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2793 * mini_llvmonly_initial_imt_tramp:
2795 * This function is called the first time a call is made through an IMT trampoline.
2796 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2799 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2801 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2806 mono_vtable_build_imt_slot (info->vtable, info->slot);
2808 imt = (gpointer*)info->vtable;
2809 imt -= MONO_IMT_SIZE;
2811 /* Return what the real IMT trampoline returns */
2812 ftndesc = imt [info->slot];
2815 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2816 /* Happens when the imt slot contains only a generic virtual method */
2818 return func ((gpointer *)ftndesc [1], imt_method);
2821 /* This is called indirectly through an imt slot. */
2823 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2827 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2828 while (arg [i] && arg [i] != imt_method)
2835 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2837 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2839 //g_assert (arg [0] == imt_method);
2844 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2846 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2847 if (arg [0] == imt_method)
2854 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2856 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2857 if (arg [0] == imt_method)
2859 else if (arg [2] == imt_method)
2866 * A version of the imt trampoline used for generic virtual/variant iface methods.
2867 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2868 * in the search table. The original JIT code had a 'fallback' trampoline it could
2869 * call, but we can't do that, so we just return NULL, and the compiled code
2873 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2877 while (arg [i] && arg [i] != imt_method)
2886 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2890 int i, index, real_count;
2891 gboolean virtual_generic = FALSE;
2894 * Create an array which is passed to the imt trampoline functions.
2895 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2899 for (i = 0; i < count; ++i) {
2900 MonoIMTCheckItem *item = imt_entries [i];
2902 if (item->is_equals)
2904 if (item->has_target_code)
2905 virtual_generic = TRUE;
2909 * Initialize all vtable entries reachable from this imt slot, so the compiled
2910 * code doesn't have to check it.
2912 for (i = 0; i < count; ++i) {
2913 MonoIMTCheckItem *item = imt_entries [i];
2916 if (!item->is_equals || item->has_target_code)
2918 vt_slot = item->value.vtable_slot;
2919 mono_init_vtable_slot (vtable, vt_slot);
2922 /* Save the entries into an array */
2923 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2925 for (i = 0; i < count; ++i) {
2926 MonoIMTCheckItem *item = imt_entries [i];
2928 if (!item->is_equals)
2931 g_assert (item->key);
2932 buf [(index * 2)] = item->key;
2933 if (item->has_target_code)
2934 buf [(index * 2) + 1] = item->value.target_code;
2936 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2939 buf [(index * 2)] = NULL;
2940 buf [(index * 2) + 1] = fail_tramp;
2943 * Return a function descriptor for a C function with 'buf' as its argument.
2944 * It will by called by JITted code.
2946 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2947 switch (real_count) {
2949 res [0] = mono_llvmonly_imt_tramp_1;
2952 res [0] = mono_llvmonly_imt_tramp_2;
2955 res [0] = mono_llvmonly_imt_tramp_3;
2958 res [0] = mono_llvmonly_imt_tramp;
2961 if (virtual_generic || fail_tramp)
2962 res [0] = mono_llvmonly_fallback_imt_tramp;
2968 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2970 MonoException *exc = NULL;
2972 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2973 MONO_SIG_HANDLER_GET_CONTEXT;
2975 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2977 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2979 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2980 if (mono_arch_is_int_overflow (ctx, info))
2982 * The spec says this throws ArithmeticException, but MS throws the derived
2983 * OverflowException.
2985 exc = mono_get_exception_overflow ();
2987 exc = mono_get_exception_divide_by_zero ();
2989 exc = mono_get_exception_divide_by_zero ();
2993 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
2996 mono_handle_native_crash ("SIGFPE", ctx, info);
2997 if (mono_do_crash_chaining) {
2998 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3003 mono_arch_handle_exception (ctx, exc);
3006 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3009 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3011 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3012 MONO_SIG_HANDLER_GET_CONTEXT;
3014 if (mono_runtime_get_no_exec ())
3018 mono_handle_native_crash ("SIGILL", ctx, info);
3019 if (mono_do_crash_chaining) {
3020 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3024 g_assert_not_reached ();
3027 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3028 #define HAVE_SIG_INFO
3031 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3034 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3035 gpointer fault_addr = NULL;
3036 #ifdef HAVE_SIG_INFO
3037 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3041 MONO_SIG_HANDLER_GET_CONTEXT;
3043 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3044 if (mono_arch_is_single_step_event (info, ctx)) {
3045 mono_debugger_agent_single_step_event (ctx);
3047 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3048 mono_debugger_agent_breakpoint_hit (ctx);
3053 #if defined(HAVE_SIG_INFO)
3054 #if !defined(HOST_WIN32)
3055 fault_addr = info->si_addr;
3056 if (mono_aot_is_pagefault (info->si_addr)) {
3057 mono_aot_handle_pagefault (info->si_addr);
3062 /* The thread might no be registered with the runtime */
3063 if (!mono_domain_get () || !jit_tls) {
3064 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3066 mono_handle_native_crash ("SIGSEGV", ctx, info);
3067 if (mono_do_crash_chaining) {
3068 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3074 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3076 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3077 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3080 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3081 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3082 fault_addr = info->si_addr;
3083 if (fault_addr == NULL) {
3086 mono_sigctx_to_monoctx (ctx, &mctx);
3088 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3092 if (jit_tls->stack_size &&
3093 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3095 * The hard-guard page has been hit: there is not much we can do anymore
3096 * Print a hopefully clear message and abort.
3098 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3099 g_assert_not_reached ();
3101 /* The original handler might not like that it is executed on an altstack... */
3102 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3105 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3110 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3113 mono_handle_native_crash ("SIGSEGV", ctx, info);
3115 if (mono_do_crash_chaining) {
3116 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3121 mono_arch_handle_exception (ctx, NULL);
3125 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3128 MONO_SIG_HANDLER_GET_CONTEXT;
3130 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3132 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3134 mono_arch_handle_exception (ctx, exc);
3136 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3139 #ifndef DISABLE_REMOTING
3140 /* mono_jit_create_remoting_trampoline:
3141 * @method: pointer to the method info
3143 * Creates a trampoline which calls the remoting functions. This
3144 * is used in the vtable of transparent proxies.
3146 * Returns: a pointer to the newly created code
3149 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3152 guint8 *addr = NULL;
3156 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3157 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3161 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3162 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3163 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3166 addr = (guint8 *)mono_compile_method_checked (nm, error);
3167 return_val_if_nok (error, NULL);
3168 return mono_get_addr_from_ftnptr (addr);
3172 static G_GNUC_UNUSED void
3173 no_imt_trampoline (void)
3175 g_assert_not_reached ();
3178 static G_GNUC_UNUSED void
3179 no_vcall_trampoline (void)
3181 g_assert_not_reached ();
3184 static gpointer *vtable_trampolines;
3185 static int vtable_trampolines_size;
3188 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3190 int index = slot_index + MONO_IMT_SIZE;
3192 if (mono_llvm_only) {
3193 if (slot_index < 0) {
3194 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3195 // FIXME: Memory management
3196 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3197 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3200 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3202 mono_memory_barrier ();
3209 g_assert (slot_index >= - MONO_IMT_SIZE);
3210 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3212 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3216 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3217 while (new_size <= index)
3219 new_table = g_new0 (gpointer, new_size);
3221 if (vtable_trampolines)
3222 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3223 g_free (vtable_trampolines);
3224 mono_memory_barrier ();
3225 vtable_trampolines = (void **)new_table;
3226 vtable_trampolines_size = new_size;
3231 if (!vtable_trampolines [index])
3232 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3233 return vtable_trampolines [index];
3237 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3239 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3243 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3248 gpointer *imt = (gpointer*)vt;
3249 imt -= MONO_IMT_SIZE;
3251 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3255 is_callee_gsharedvt_variable (gpointer addr)
3258 gboolean callee_gsharedvt;
3260 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3262 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3263 if (callee_gsharedvt)
3264 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3265 return callee_gsharedvt;
3269 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3271 gpointer arg = NULL;
3273 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3274 arg = mini_method_get_rgctx (method);
3277 * Avoid adding gsharedvt in wrappers since they might not exist if
3278 * this delegate is called through a gsharedvt delegate invoke wrapper.
3279 * Instead, encode that the method is gsharedvt in del->extra_arg,
3280 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3282 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3283 g_assert ((((mgreg_t)arg) & 1) == 0);
3284 arg = (gpointer)(((mgreg_t)arg) | 1);
3290 mini_init_delegate (MonoDelegate *del)
3293 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3294 #ifdef ENABLE_INTERPRETER
3295 if (mono_use_interpreter)
3296 mono_interp_init_delegate (del);
3301 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3305 abs_offset = offset;
3307 abs_offset = - abs_offset;
3308 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3312 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3314 gboolean is_virtual_generic, is_interface, load_imt_reg;
3317 static guint8 **cache = NULL;
3318 static int cache_size = 0;
3323 if (MONO_TYPE_ISSTRUCT (sig->ret))
3326 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3327 is_interface = mono_class_is_interface (method->klass);
3328 load_imt_reg = is_virtual_generic || is_interface;
3331 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3333 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3335 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3336 g_assert (idx >= 0);
3338 /* Resize the cache to idx + 1 */
3339 if (cache_size < idx + 1) {
3341 if (cache_size < idx + 1) {
3343 int new_cache_size = idx + 1;
3345 new_cache = g_new0 (guint8*, new_cache_size);
3347 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3350 mono_memory_barrier ();
3352 cache_size = new_cache_size;
3360 /* FIXME Support more cases */
3361 if (mono_aot_only) {
3362 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3363 g_assert (cache [idx]);
3365 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3371 * mini_parse_debug_option:
3372 * @option: The option to parse.
3374 * Parses debug options for the mono runtime. The options are the same as for
3375 * the MONO_DEBUG environment variable.
3379 mini_parse_debug_option (const char *option)
3381 if (!strcmp (option, "handle-sigint"))
3382 debug_options.handle_sigint = TRUE;
3383 else if (!strcmp (option, "keep-delegates"))
3384 debug_options.keep_delegates = TRUE;
3385 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3386 debug_options.reverse_pinvoke_exceptions = TRUE;
3387 else if (!strcmp (option, "collect-pagefault-stats"))
3388 debug_options.collect_pagefault_stats = TRUE;
3389 else if (!strcmp (option, "break-on-unverified"))
3390 debug_options.break_on_unverified = TRUE;
3391 else if (!strcmp (option, "no-gdb-backtrace"))
3392 debug_options.no_gdb_backtrace = TRUE;
3393 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3394 debug_options.suspend_on_native_crash = TRUE;
3395 else if (!strcmp (option, "suspend-on-exception"))
3396 debug_options.suspend_on_exception = TRUE;
3397 else if (!strcmp (option, "suspend-on-unhandled"))
3398 debug_options.suspend_on_unhandled = TRUE;
3399 else if (!strcmp (option, "dont-free-domains"))
3400 mono_dont_free_domains = TRUE;
3401 else if (!strcmp (option, "dyn-runtime-invoke"))
3402 debug_options.dyn_runtime_invoke = TRUE;
3403 else if (!strcmp (option, "gdb"))
3404 debug_options.gdb = TRUE;
3405 else if (!strcmp (option, "lldb"))
3406 debug_options.lldb = TRUE;
3407 else if (!strcmp (option, "explicit-null-checks"))
3408 debug_options.explicit_null_checks = TRUE;
3409 else if (!strcmp (option, "gen-seq-points"))
3410 debug_options.gen_sdb_seq_points = TRUE;
3411 else if (!strcmp (option, "gen-compact-seq-points"))
3412 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3413 else if (!strcmp (option, "no-compact-seq-points"))
3414 debug_options.no_seq_points_compact_data = TRUE;
3415 else if (!strcmp (option, "single-imm-size"))
3416 debug_options.single_imm_size = TRUE;
3417 else if (!strcmp (option, "init-stacks"))
3418 debug_options.init_stacks = TRUE;
3419 else if (!strcmp (option, "casts"))
3420 debug_options.better_cast_details = TRUE;
3421 else if (!strcmp (option, "soft-breakpoints"))
3422 debug_options.soft_breakpoints = TRUE;
3423 else if (!strcmp (option, "check-pinvoke-callconv"))
3424 debug_options.check_pinvoke_callconv = TRUE;
3425 else if (!strcmp (option, "use-fallback-tls"))
3426 debug_options.use_fallback_tls = TRUE;
3427 else if (!strcmp (option, "debug-domain-unload"))
3428 mono_enable_debug_domain_unload (TRUE);
3429 else if (!strcmp (option, "partial-sharing"))
3430 mono_set_partial_sharing_supported (TRUE);
3431 else if (!strcmp (option, "align-small-structs"))
3432 mono_align_small_structs = TRUE;
3433 else if (!strcmp (option, "native-debugger-break"))
3434 debug_options.native_debugger_break = TRUE;
3435 else if (!strcmp (option, "disable_omit_fp"))
3436 debug_options.disable_omit_fp = TRUE;
3444 mini_parse_debug_options (void)
3446 char *options = g_getenv ("MONO_DEBUG");
3447 gchar **args, **ptr;
3452 args = g_strsplit (options, ",", -1);
3455 for (ptr = args; ptr && *ptr; ptr++) {
3456 const char *arg = *ptr;
3458 if (!mini_parse_debug_option (arg)) {
3459 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3460 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");
3469 mini_get_debug_options (void)
3471 return &debug_options;
3475 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3477 #if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3480 gpointer* desc = NULL;
3482 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3485 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
3489 # elif defined(__ppc64__) || defined(__powerpc64__)
3491 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3497 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3503 mini_get_addr_from_ftnptr (gpointer descr)
3505 #if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3506 return *(gpointer*)descr;
3513 register_jit_stats (void)
3515 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3516 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3517 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3518 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3519 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3520 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3521 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);
3522 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3523 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3524 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3525 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3526 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3527 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3528 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3529 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3530 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3531 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3532 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3533 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3534 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3535 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3536 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3537 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3538 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3539 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3540 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3541 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3542 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3543 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3544 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3545 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3546 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3547 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3548 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3549 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3550 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3551 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3552 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3553 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3554 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3555 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3556 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3557 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3558 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3559 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3560 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3561 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3562 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3563 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3564 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3565 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3566 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3567 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3568 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3569 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3570 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3571 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3572 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3573 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3574 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3575 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3578 static void runtime_invoke_info_free (gpointer value);
3581 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3583 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3584 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3586 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3590 class_method_pair_hash (gconstpointer data)
3592 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3594 return (gsize)pair->klass ^ (gsize)pair->method;
3598 mini_create_jit_domain_info (MonoDomain *domain)
3600 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3602 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3603 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3604 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3605 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3606 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3607 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3608 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3609 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3610 mono_jit_code_hash_init (&info->interp_code_hash);
3612 domain->runtime_info = info;
3616 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3618 MonoJumpList *jlist = (MonoJumpList *)value;
3619 g_slist_free (jlist->list);
3623 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3625 GSList *list = (GSList *)value;
3626 g_slist_free (list);
3630 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3632 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3633 mono_code_manager_destroy (di->code_mp);
3638 runtime_invoke_info_free (gpointer value)
3640 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3642 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3643 if (info->dyn_call_info)
3644 mono_arch_dyn_call_free (info->dyn_call_info);
3650 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3652 g_slist_free (value);
3656 mini_free_jit_domain_info (MonoDomain *domain)
3658 MonoJitDomainInfo *info = domain_jit_info (domain);
3660 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3661 g_hash_table_destroy (info->jump_target_hash);
3662 if (info->jump_target_got_slot_hash) {
3663 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3664 g_hash_table_destroy (info->jump_target_got_slot_hash);
3666 if (info->dynamic_code_hash) {
3667 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3668 g_hash_table_destroy (info->dynamic_code_hash);
3670 if (info->method_code_hash)
3671 g_hash_table_destroy (info->method_code_hash);
3672 g_hash_table_destroy (info->jump_trampoline_hash);
3673 g_hash_table_destroy (info->jit_trampoline_hash);
3674 g_hash_table_destroy (info->delegate_trampoline_hash);
3675 if (info->static_rgctx_trampoline_hash)
3676 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3677 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3678 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3679 g_hash_table_destroy (info->seq_points);
3680 g_hash_table_destroy (info->arch_seq_points);
3681 if (info->agent_info)
3682 mono_debugger_agent_free_domain_info (domain);
3683 if (info->gsharedvt_arg_tramp_hash)
3684 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3685 if (info->llvm_jit_callees) {
3686 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3687 g_hash_table_destroy (info->llvm_jit_callees);
3689 mono_internal_hash_table_destroy (&info->interp_code_hash);
3691 mono_llvm_free_domain_info (domain);
3694 g_free (domain->runtime_info);
3695 domain->runtime_info = NULL;
3698 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3701 code_manager_chunk_new (void *chunk, int size)
3703 mono_arch_code_chunk_new (chunk, size);
3707 code_manager_chunk_destroy (void *chunk)
3709 mono_arch_code_chunk_destroy (chunk);
3716 llvm_init_inner (void)
3718 if (!mono_llvm_load (NULL))
3729 * Load and initialize LLVM support.
3730 * Return TRUE on success.
3733 mini_llvm_init (void)
3736 static gboolean llvm_inited;
3737 static gboolean init_result;
3739 mono_loader_lock_if_inited ();
3741 init_result = llvm_init_inner ();
3744 mono_loader_unlock_if_inited ();
3752 mini_profiler_enable_with_options (const char* profile_options)
3754 mini_enable_profiler = TRUE;
3755 mini_profiler_options = g_strdup (profile_options);
3759 mini_init (const char *filename, const char *runtime_version)
3763 MonoRuntimeCallbacks callbacks;
3764 MonoThreadInfoRuntimeCallbacks ticallbacks;
3765 MonoCodeManagerCallbacks code_manager_callbacks;
3767 MONO_VES_INIT_BEGIN ();
3769 CHECKED_MONO_INIT ();
3771 #if defined(__linux__) && !defined(__native_client__)
3772 if (access ("/proc/self/maps", F_OK) != 0) {
3773 g_print ("Mono requires /proc to be mounted.\n");
3778 #ifdef ENABLE_INTERPRETER
3779 mono_interp_init ();
3782 mono_os_mutex_init_recursive (&jit_mutex);
3784 mono_cross_helpers_run ();
3786 mono_counters_init ();
3790 mini_jit_init_job_control ();
3792 /* Happens when using the embedding interface */
3793 if (!default_opt_set)
3794 default_opt = mono_parse_default_optimizations (NULL);
3796 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3798 mono_set_generic_sharing_vt_supported (TRUE);
3801 mono_set_generic_sharing_vt_supported (TRUE);
3804 mono_tls_init_runtime_keys ();
3806 if (!global_codeman)
3807 global_codeman = mono_code_manager_new ();
3809 memset (&callbacks, 0, sizeof (callbacks));
3810 callbacks.create_ftnptr = mini_create_ftnptr;
3811 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3812 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3813 callbacks.set_cast_details = mono_set_cast_details;
3814 callbacks.debug_log = mono_debugger_agent_debug_log;
3815 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3816 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3817 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3818 callbacks.imt_entry_inited = mini_imt_entry_inited;
3819 callbacks.init_delegate = mini_init_delegate;
3820 #define JIT_INVOKE_WORKS
3821 #ifdef JIT_INVOKE_WORKS
3822 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3824 #define JIT_TRAMPOLINES_WORK
3825 #ifdef JIT_TRAMPOLINES_WORK
3826 callbacks.compile_method = mono_jit_compile_method;
3827 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3828 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3829 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3830 callbacks.free_method = mono_jit_free_method;
3831 #ifndef DISABLE_REMOTING
3832 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3836 mono_install_callbacks (&callbacks);
3838 memset (&ticallbacks, 0, sizeof (ticallbacks));
3839 ticallbacks.setup_async_callback = mono_setup_async_callback;
3840 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3841 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3842 ticallbacks.thread_state_init = mono_thread_state_init;
3845 mono_w32handle_init ();
3848 mono_threads_runtime_init (&ticallbacks);
3850 if (g_hasenv ("MONO_DEBUG")) {
3851 mini_parse_debug_options ();
3854 mono_code_manager_init ();
3856 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3857 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3858 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3859 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3861 mono_code_manager_install_callbacks (&code_manager_callbacks);
3865 mono_arch_cpu_init ();
3869 mono_unwind_init ();
3871 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3872 mono_lldb_init ("");
3873 mono_dont_free_domains = TRUE;
3876 #ifdef XDEBUG_ENABLED
3877 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3879 mono_xdebug_init (mono_xdebug);
3880 g_free (mono_xdebug);
3881 /* So methods for multiple domains don't have the same address */
3882 mono_dont_free_domains = TRUE;
3883 mono_using_xdebug = TRUE;
3884 } else if (mini_get_debug_options ()->gdb) {
3885 mono_xdebug_init ((char*)"gdb");
3886 mono_dont_free_domains = TRUE;
3887 mono_using_xdebug = TRUE;
3892 if (mono_use_llvm) {
3893 if (!mono_llvm_load (NULL)) {
3894 mono_use_llvm = FALSE;
3895 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3902 mono_trampolines_init ();
3904 if (default_opt & MONO_OPT_AOT)
3907 mono_debugger_agent_init ();
3909 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3910 mono_set_generic_sharing_supported (TRUE);
3913 mono_threads_signals_init ();
3915 #ifndef MONO_CROSS_COMPILE
3916 mono_runtime_install_handlers ();
3918 mono_threads_install_cleanup (mini_thread_cleanup);
3920 #ifdef JIT_TRAMPOLINES_WORK
3921 mono_install_create_domain_hook (mini_create_jit_domain_info);
3922 mono_install_free_domain_hook (mini_free_jit_domain_info);
3924 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3925 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3926 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3928 if (mini_profiler_enabled ()) {
3929 mono_profiler_load (mini_profiler_get_options ());
3930 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3933 if (debug_options.collect_pagefault_stats)
3934 mono_aot_set_make_unreadable (TRUE);
3936 if (runtime_version)
3937 domain = mono_init_version (filename, runtime_version);
3939 domain = mono_init_from_assembly (filename, filename);
3941 if (mono_aot_only) {
3942 /* This helps catch code allocation requests */
3943 mono_code_manager_set_read_only (domain->code_mp);
3944 mono_marshal_use_aot_wrappers (TRUE);
3947 if (mono_llvm_only) {
3948 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3949 mono_set_always_build_imt_trampolines (TRUE);
3950 } else if (mono_aot_only) {
3951 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3953 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3956 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3957 mono_arch_finish_init ();
3961 /* This must come after mono_init () in the aot-only case */
3962 mono_exceptions_init ();
3964 /* This should come after mono_init () too */
3968 mono_create_helper_signatures ();
3971 register_jit_stats ();
3973 #define JIT_CALLS_WORK
3974 #ifdef JIT_CALLS_WORK
3975 /* Needs to be called here since register_jit_icall depends on it */
3976 mono_marshal_init ();
3978 mono_arch_register_lowlevel_calls ();
3982 mono_generic_sharing_init ();
3985 #ifdef MONO_ARCH_SIMD_INTRINSICS
3986 mono_simd_intrinsics_init ();
3989 mono_tasklets_init ();
3991 register_trampolines (domain);
3993 if (mono_compile_aot)
3995 * Avoid running managed code when AOT compiling, since the platform
3996 * might only support aot-only execution.
3998 mono_runtime_set_no_exec (TRUE);
4000 mono_mem_account_register_counters ();
4002 #define JIT_RUNTIME_WORKS
4003 #ifdef JIT_RUNTIME_WORKS
4004 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4005 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
4006 mono_error_assert_ok (&error);
4007 mono_thread_attach (domain);
4010 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4011 mono_runtime_setup_stat_profiler ();
4013 mono_profiler_runtime_initialized ();
4015 MONO_VES_INIT_END ();
4021 register_icalls (void)
4023 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4024 ves_icall_get_frame_info);
4025 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4026 ves_icall_get_trace);
4027 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4028 mono_runtime_install_handlers);
4029 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4030 mono_runtime_cleanup_handlers);
4032 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4033 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4034 mono_debugger_agent_unhandled_exception);
4038 * It's important that we pass `TRUE` as the last argument here, as
4039 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4040 * *did* emit a wrapper, we'd be looking at infinite recursion since
4041 * the wrapper would call the icall which would call the wrapper and
4044 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4045 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4047 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4048 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4049 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4050 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4051 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4052 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4054 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4055 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4056 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4057 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4058 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4059 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4060 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4061 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4062 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4064 // FIXME: This is broken
4065 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4068 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4069 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4070 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4071 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4072 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4073 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4075 #if defined(__native_client__) || defined(__native_client_codegen__)
4076 register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
4079 if (mono_threads_is_coop_enabled ())
4080 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4082 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4083 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4084 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4085 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4086 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4087 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4089 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4090 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4091 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4094 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4095 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4096 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4097 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4100 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4101 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4102 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4103 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4104 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4107 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4108 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4111 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4112 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4113 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4116 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4117 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4120 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4121 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4122 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4123 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4124 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4125 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4126 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4129 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4130 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4131 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4134 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4135 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);
4137 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4138 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4140 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4141 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4143 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4144 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);
4146 #ifdef MONO_ARCH_EMULATE_FREM
4147 #if !defined(__native_client__)
4148 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4149 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4151 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
4155 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4156 if (mono_arch_is_soft_float ()) {
4157 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4158 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4159 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4160 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4161 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4162 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4163 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4164 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4165 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4166 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4167 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4168 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4170 #if SIZEOF_VOID_P == 4
4171 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4174 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4175 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4176 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4177 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4178 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4179 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4180 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4181 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4182 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4183 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4185 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4186 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4187 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4188 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4189 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4191 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4192 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4193 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4194 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4197 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4199 #ifdef COMPRESSED_INTERFACE_BITMAP
4200 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4203 #if SIZEOF_REGISTER == 4
4204 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4206 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4209 /* other jit icalls */
4210 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4211 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4212 "ptr ptr ptr", FALSE);
4213 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4214 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4215 "ptr ptr ptr ptr", FALSE);
4216 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4217 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4218 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4219 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4220 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4221 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4222 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4223 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4224 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4225 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4226 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4227 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4228 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4229 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4230 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4231 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4232 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4233 register_icall (mono_break, "mono_break", NULL, TRUE);
4234 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4235 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4236 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4237 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4238 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4239 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4240 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4241 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4242 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4243 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4244 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4246 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int");
4248 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4249 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4250 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4251 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4252 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4254 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4256 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4257 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4258 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4259 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4261 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4262 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4263 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4264 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4265 /* This needs a wrapper so it can have a preserveall cconv */
4266 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4267 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4268 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4269 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4270 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4271 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4272 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4274 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4275 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4276 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4277 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4280 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4282 /* Register tls icalls */
4283 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4284 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4285 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4286 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4287 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4288 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4289 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4290 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4291 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4292 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4295 MonoJitStats mono_jit_stats = {0};
4298 print_jit_stats (void)
4300 if (mono_jit_stats.enabled) {
4301 g_print ("Mono Jit statistics\n");
4302 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4303 mono_jit_stats.max_ratio_method);
4304 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4305 mono_jit_stats.biggest_method);
4307 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4308 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4309 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4310 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4311 g_print ("Methods: %ld\n", mono_stats.method_count);
4312 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4313 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4314 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4316 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4317 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4318 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4320 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4321 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4322 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4323 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4325 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4326 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4327 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4328 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4329 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4330 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4331 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4332 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4334 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4335 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4336 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4338 g_free (mono_jit_stats.max_ratio_method);
4339 mono_jit_stats.max_ratio_method = NULL;
4340 g_free (mono_jit_stats.biggest_method);
4341 mono_jit_stats.biggest_method = NULL;
4346 mini_cleanup (MonoDomain *domain)
4348 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4349 mono_runtime_shutdown_stat_profiler ();
4352 cominterop_release_all_rcws ();
4355 #ifndef MONO_CROSS_COMPILE
4357 * mono_domain_finalize () needs to be called early since it needs the
4358 * execution engine still fully working (it may invoke managed finalizers).
4360 mono_domain_finalize (domain, 2000);
4363 /* This accesses metadata so needs to be called before runtime shutdown */
4366 #ifndef MONO_CROSS_COMPILE
4367 mono_runtime_cleanup (domain);
4370 mono_threadpool_cleanup ();
4372 mono_profiler_shutdown ();
4374 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4376 mono_icall_cleanup ();
4378 mono_runtime_cleanup_handlers ();
4380 #ifndef MONO_CROSS_COMPILE
4381 mono_domain_free (domain, TRUE);
4386 mono_llvm_cleanup ();
4389 mono_aot_cleanup ();
4391 mono_trampolines_cleanup ();
4393 mono_unwind_cleanup ();
4395 mono_code_manager_destroy (global_codeman);
4396 g_free (vtable_trampolines);
4398 mini_jit_cleanup ();
4400 mono_tramp_info_cleanup ();
4402 mono_arch_cleanup ();
4404 mono_generic_sharing_cleanup ();
4408 mono_trace_cleanup ();
4410 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4412 if (mono_inject_async_exc_method)
4413 mono_method_desc_free (mono_inject_async_exc_method);
4415 mono_tls_free_keys ();
4417 mono_os_mutex_destroy (&jit_mutex);
4419 mono_code_manager_cleanup ();
4422 mono_w32handle_cleanup ();
4427 mono_set_defaults (int verbose_level, guint32 opts)
4429 mini_verbose = verbose_level;
4430 mono_set_optimizations (opts);
4434 mono_disable_optimizations (guint32 opts)
4436 default_opt &= ~opts;
4440 mono_set_optimizations (guint32 opts)
4443 default_opt_set = TRUE;
4444 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4445 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4448 mono_set_generic_sharing_vt_supported (TRUE);
4453 mono_set_verbose_level (guint32 level)
4455 mini_verbose = level;
4459 * mono_get_runtime_build_info:
4460 * The returned string is owned by the caller. The returned string
4461 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4462 * \returns the runtime version + build date in string format.
4465 mono_get_runtime_build_info (void)
4467 if (mono_build_date)
4468 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4470 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4474 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4476 GHashTable *assemblies = (GHashTable*)user_data;
4477 MonoImage *image = mono_assembly_get_image (ass);
4478 MonoMethod *method, *invoke;
4481 if (g_hash_table_lookup (assemblies, ass))
4484 g_hash_table_insert (assemblies, ass, ass);
4486 if (mini_verbose > 0)
4487 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4489 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4492 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4494 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4497 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4499 if (method->is_generic || mono_class_is_gtd (method->klass))
4503 if (mini_verbose > 1) {
4504 char * desc = mono_method_full_name (method, TRUE);
4505 g_print ("Compiling %d %s\n", count, desc);
4508 mono_compile_method_checked (method, &error);
4509 if (!is_ok (&error)) {
4510 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4513 if (strcmp (method->name, "Finalize") == 0) {
4514 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4515 mono_compile_method_checked (invoke, &error);
4516 mono_error_assert_ok (&error);
4518 #ifndef DISABLE_REMOTING
4519 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4520 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4521 mono_compile_method_checked (invoke, &error);
4522 mono_error_assert_ok (&error);
4527 /* Load and precompile referenced assemblies as well */
4528 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4529 mono_assembly_load_reference (image, i);
4530 if (image->references [i])
4531 mono_precompile_assembly (image->references [i], assemblies);
4535 void mono_precompile_assemblies ()
4537 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4539 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4541 g_hash_table_destroy (assemblies);
4546 * Have to export this for AOT.
4549 mono_personality (void)
4552 g_assert_not_reached ();
4555 // Custom handlers currently only implemented by Windows.
4558 mono_runtime_install_custom_handlers (const char *handlers)
4564 mono_runtime_install_custom_handlers_usage (void)
4567 "Custom Handlers:\n"
4568 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4569 " separated list of available handlers to install.\n"
4571 "No handlers supported on current platform.\n");
4573 #endif /* HOST_WIN32 */