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 /* Trampolines from aot have the unwind ops already encoded */
501 copy->uw_info = info->uw_info;
502 copy->uw_info_len = info->uw_info_len;
505 mono_save_trampoline_xdebug_info (info);
506 mono_lldb_save_trampoline_info (info);
508 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
510 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
514 /* If no root domain has been created yet, postpone the registration. */
516 tramp_infos = g_slist_prepend (tramp_infos, copy);
518 } else if (copy->uw_info) {
519 /* Only register trampolines that have unwind infos */
520 register_trampoline_jit_info (domain, copy);
523 if (mono_jit_map_is_enabled ())
524 mono_emit_jit_tramp (info->code, info->code_size, info->name);
526 mono_tramp_info_free (info);
530 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
532 mono_tramp_info_register_internal (info, domain, FALSE);
536 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
538 mono_tramp_info_register_internal (info, domain, TRUE);
542 mono_tramp_info_cleanup (void)
546 for (l = tramp_infos; l; l = l->next) {
547 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
549 mono_tramp_info_free (info);
551 g_slist_free (tramp_infos);
554 /* Register trampolines created before the root domain was created in the jit info tables */
556 register_trampolines (MonoDomain *domain)
560 for (l = tramp_infos; l; l = l->next) {
561 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
563 register_trampoline_jit_info (domain, info);
567 G_GNUC_UNUSED static void
573 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
574 * Set a breakpoint in break_count () to break the last time <x> is done.
576 G_GNUC_UNUSED gboolean
577 mono_debug_count (void)
579 static int count = 0;
580 static gboolean inited;
586 value = g_getenv ("COUNT");
593 int int_val = atoi (value);
596 if (count == int_val)
606 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
611 gconstpointer trampoline;
612 MonoDomain *domain = mono_get_root_domain ();
613 gboolean check_exc = TRUE;
615 if (callinfo->wrapper)
616 return callinfo->wrapper;
618 if (callinfo->trampoline)
619 return callinfo->trampoline;
621 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
622 /* This icall is used to check for exceptions, so don't check in the wrapper */
625 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
626 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
630 trampoline = mono_compile_method_checked (wrapper, &error);
631 mono_error_assert_ok (&error);
634 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
635 mono_error_assert_ok (&error);
636 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
640 if (!callinfo->trampoline) {
641 mono_register_jit_icall_wrapper (callinfo, trampoline);
642 callinfo->trampoline = trampoline;
644 mono_loader_unlock ();
646 return callinfo->trampoline;
650 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
652 return mono_icall_get_wrapper_full (callinfo, FALSE);
655 static MonoJitDynamicMethodInfo*
656 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
658 MonoJitDynamicMethodInfo *res;
660 if (domain_jit_info (domain)->dynamic_code_hash)
661 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
668 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
671 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
673 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
675 g_assert (!sig->hasthis);
676 g_assert (sig->param_count < 3);
678 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
679 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
684 * For JIT icalls implemented in C.
685 * NAME should be the same as the name of the C function whose address is FUNC.
686 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
687 * can't throw exceptions.
690 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
692 MonoMethodSignature *sig;
695 sig = mono_create_icall_signature (sigstr);
699 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
703 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
705 MonoMethodSignature *sig;
708 sig = mono_create_icall_signature (sigstr);
712 mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
716 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
718 MonoMethodSignature *sig;
721 sig = mono_create_icall_signature (sigstr);
725 mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
729 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
731 MonoMethodSignature *sig;
734 sig = mono_create_icall_signature (sigstr);
738 mono_register_jit_icall (func, name, sig, save);
744 MonoJitTlsData *jit_tls;
746 if ((jit_tls = mono_tls_get_jit_tls ()))
749 * We do not assert here because this function can be called from
750 * mini-gc.c on a thread that has not executed any managed code, yet
751 * (the thread object allocation can trigger a collection).
757 mono_get_lmf_addr (void)
759 return (MonoLMF **)mono_tls_get_lmf_addr ();
763 mono_set_lmf (MonoLMF *lmf)
765 (*mono_get_lmf_addr ()) = lmf;
769 mono_get_jit_tls (void)
771 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
775 mono_set_jit_tls (MonoJitTlsData *jit_tls)
777 MonoThreadInfo *info;
779 mono_tls_set_jit_tls (jit_tls);
781 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
782 info = mono_thread_info_current ();
784 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
788 mono_set_lmf_addr (gpointer lmf_addr)
790 MonoThreadInfo *info;
792 mono_tls_set_lmf_addr (lmf_addr);
794 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
795 info = mono_thread_info_current ();
797 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
803 * Push an MonoLMFExt frame on the LMF stack.
806 mono_push_lmf (MonoLMFExt *ext)
808 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
811 lmf_addr = mono_get_lmf_addr ();
813 mono_arch_init_lmf_ext (ext, *lmf_addr);
815 mono_set_lmf ((MonoLMF*)ext);
824 * Pop the last frame from the LMF stack.
827 mono_pop_lmf (MonoLMF *lmf)
829 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
833 * mono_jit_thread_attach:
835 * Called by Xamarin.Mac and other products. Attach thread to runtime if
836 * needed and switch to @domain.
838 * @return the original domain which needs to be restored, or NULL.
841 mono_jit_thread_attach (MonoDomain *domain)
846 g_assert (!mono_threads_is_coop_enabled ());
849 /* Happens when called from AOTed code which is only used in the root domain. */
850 domain = mono_get_root_domain ();
855 attached = mono_tls_get_jit_tls () != NULL;
858 mono_thread_attach (domain);
861 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
864 orig = mono_domain_get ();
866 mono_domain_set (domain, TRUE);
868 return orig != domain ? orig : NULL;
872 * mono_jit_set_domain:
874 * Set domain to @domain if @domain is not null
877 mono_jit_set_domain (MonoDomain *domain)
879 g_assert (!mono_threads_is_coop_enabled ());
882 mono_domain_set (domain, TRUE);
887 * \param obj exception object
888 * Abort the thread, print exception information and stack trace
891 mono_thread_abort (MonoObject *obj)
893 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
895 /* handle_remove should be eventually called for this thread, too
898 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
899 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
902 mono_invoke_unhandled_exception_hook (obj);
907 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
909 MonoJitTlsData *jit_tls;
912 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
916 jit_tls = g_new0 (MonoJitTlsData, 1);
918 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
919 jit_tls->end_of_stack = stack_start;
921 mono_set_jit_tls (jit_tls);
923 lmf = g_new0 (MonoLMF, 1);
924 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
926 jit_tls->first_lmf = lmf;
928 mono_set_lmf_addr (&jit_tls->lmf);
932 #ifdef MONO_ARCH_HAVE_TLS_INIT
933 mono_arch_tls_init ();
936 mono_setup_altstack (jit_tls);
942 free_jit_tls_data (MonoJitTlsData *jit_tls)
944 mono_arch_free_jit_tls_data (jit_tls);
945 mono_free_altstack (jit_tls);
947 g_free (jit_tls->first_lmf);
952 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
954 MonoThreadInfo *thread;
955 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
956 thread = mono_thread_info_current_unchecked ();
958 thread->jit_data = jit_tls;
960 mono_arch_cpu_init ();
963 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
966 mono_thread_abort_dummy (MonoObject *obj)
968 if (mono_thread_attach_aborted_cb)
969 mono_thread_attach_aborted_cb (obj);
971 mono_thread_abort (obj);
975 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
977 MonoThreadInfo *thread;
978 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
979 thread = mono_thread_info_current_unchecked ();
981 thread->jit_data = jit_tls;
983 mono_arch_cpu_init ();
987 mini_thread_cleanup (MonoNativeThreadId tid)
989 MonoJitTlsData *jit_tls = NULL;
990 MonoThreadInfo *info;
992 info = mono_thread_info_current_unchecked ();
994 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
995 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
996 * not a trivial thing.
998 * The current offender is mono_thread_manage which cleanup threads from the outside.
1000 if (info && mono_thread_info_get_tid (info) == tid) {
1001 jit_tls = (MonoJitTlsData *)info->jit_data;
1002 info->jit_data = NULL;
1004 mono_set_jit_tls (NULL);
1006 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1007 if (mono_get_lmf ()) {
1008 mono_set_lmf (NULL);
1009 mono_set_lmf_addr (NULL);
1012 info = mono_thread_info_lookup (tid);
1014 jit_tls = (MonoJitTlsData *)info->jit_data;
1015 info->jit_data = NULL;
1017 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1021 free_jit_tls_data (jit_tls);
1025 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1027 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1031 ji->data.target = target;
1037 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1039 static const char* const patch_info_str[] = {
1040 #define PATCH_INFO(a,b) "" #a,
1041 #include "patch-info.h"
1046 mono_ji_type_to_string (MonoJumpInfoType type)
1048 return patch_info_str [type];
1052 mono_print_ji (const MonoJumpInfo *ji)
1055 case MONO_PATCH_INFO_RGCTX_FETCH: {
1056 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1058 printf ("[RGCTX_FETCH ");
1059 mono_print_ji (entry->data);
1060 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1063 case MONO_PATCH_INFO_METHODCONST: {
1064 char *s = mono_method_full_name (ji->data.method, TRUE);
1065 printf ("[METHODCONST - %s]", s);
1069 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1070 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1074 printf ("[%s]", patch_info_str [ji->type]);
1082 mono_ji_type_to_string (MonoJumpInfoType type)
1088 mono_print_ji (const MonoJumpInfo *ji)
1095 * mono_patch_info_dup_mp:
1097 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1100 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1102 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1103 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1105 switch (patch_info->type) {
1106 case MONO_PATCH_INFO_RVA:
1107 case MONO_PATCH_INFO_LDSTR:
1108 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1109 case MONO_PATCH_INFO_LDTOKEN:
1110 case MONO_PATCH_INFO_DECLSEC:
1111 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1112 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1114 case MONO_PATCH_INFO_SWITCH:
1115 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1116 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1117 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1118 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1120 case MONO_PATCH_INFO_RGCTX_FETCH:
1121 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1122 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1123 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1124 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1126 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1127 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1128 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1130 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1131 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1132 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1134 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1135 MonoGSharedVtMethodInfo *info;
1136 MonoGSharedVtMethodInfo *oinfo;
1139 oinfo = patch_info->data.gsharedvt_method;
1140 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1141 res->data.gsharedvt_method = info;
1142 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1143 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1144 for (i = 0; i < oinfo->num_entries; ++i) {
1145 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1146 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1148 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1150 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1151 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1154 case MONO_PATCH_INFO_VIRT_METHOD: {
1155 MonoJumpInfoVirtMethod *info;
1156 MonoJumpInfoVirtMethod *oinfo;
1158 oinfo = patch_info->data.virt_method;
1159 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1160 res->data.virt_method = info;
1161 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1172 mono_patch_info_hash (gconstpointer data)
1174 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1177 case MONO_PATCH_INFO_RVA:
1178 case MONO_PATCH_INFO_LDSTR:
1179 case MONO_PATCH_INFO_LDTOKEN:
1180 case MONO_PATCH_INFO_DECLSEC:
1181 return (ji->type << 8) | ji->data.token->token;
1182 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1183 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1184 case MONO_PATCH_INFO_INTERNAL_METHOD:
1185 return (ji->type << 8) | g_str_hash (ji->data.name);
1186 case MONO_PATCH_INFO_VTABLE:
1187 case MONO_PATCH_INFO_CLASS:
1188 case MONO_PATCH_INFO_IID:
1189 case MONO_PATCH_INFO_ADJUSTED_IID:
1190 case MONO_PATCH_INFO_METHODCONST:
1191 case MONO_PATCH_INFO_METHOD:
1192 case MONO_PATCH_INFO_METHOD_JUMP:
1193 case MONO_PATCH_INFO_IMAGE:
1194 case MONO_PATCH_INFO_ICALL_ADDR:
1195 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1196 case MONO_PATCH_INFO_FIELD:
1197 case MONO_PATCH_INFO_SFLDA:
1198 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1199 case MONO_PATCH_INFO_METHOD_RGCTX:
1200 case MONO_PATCH_INFO_SIGNATURE:
1201 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1202 case MONO_PATCH_INFO_AOT_JIT_INFO:
1203 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1204 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1205 return (ji->type << 8) | (gssize)ji->data.target;
1206 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1207 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1208 case MONO_PATCH_INFO_RGCTX_FETCH:
1209 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1210 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1212 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1214 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1215 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1216 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1217 case MONO_PATCH_INFO_GC_NURSERY_START:
1218 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1219 case MONO_PATCH_INFO_GOT_OFFSET:
1220 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1221 case MONO_PATCH_INFO_AOT_MODULE:
1222 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1223 return (ji->type << 8);
1224 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1225 return (ji->type << 8) | (ji->data.index);
1226 case MONO_PATCH_INFO_SWITCH:
1227 return (ji->type << 8) | ji->data.table->table_size;
1228 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1229 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1230 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1231 /* Hash on the selector name */
1232 return g_str_hash (ji->data.target);
1233 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1234 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1235 case MONO_PATCH_INFO_LDSTR_LIT:
1236 return g_str_hash (ji->data.target);
1237 case MONO_PATCH_INFO_VIRT_METHOD: {
1238 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1240 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1242 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1243 return (ji->type << 8) | g_str_hash (ji->data.target);
1244 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1245 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1247 printf ("info type: %d\n", ji->type);
1248 mono_print_ji (ji); printf ("\n");
1249 g_assert_not_reached ();
1255 * mono_patch_info_equal:
1257 * This might fail to recognize equivalent patches, i.e. floats, so its only
1258 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1262 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1264 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1265 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1267 if (ji1->type != ji2->type)
1270 switch (ji1->type) {
1271 case MONO_PATCH_INFO_RVA:
1272 case MONO_PATCH_INFO_LDSTR:
1273 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1274 case MONO_PATCH_INFO_LDTOKEN:
1275 case MONO_PATCH_INFO_DECLSEC:
1276 if ((ji1->data.token->image != ji2->data.token->image) ||
1277 (ji1->data.token->token != ji2->data.token->token) ||
1278 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1279 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1280 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1283 case MONO_PATCH_INFO_INTERNAL_METHOD:
1284 return g_str_equal (ji1->data.name, ji2->data.name);
1285 case MONO_PATCH_INFO_RGCTX_FETCH:
1286 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1287 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1288 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1290 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);
1292 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1293 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1294 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1296 return c1->sig == c2->sig && c1->method == c2->method;
1298 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1299 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1300 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1301 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;
1302 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1303 return ji1->data.index == ji2->data.index;
1304 case MONO_PATCH_INFO_VIRT_METHOD:
1305 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1306 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1307 if (ji1->data.target == ji2->data.target)
1309 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1310 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1311 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1313 if (ji1->data.target != ji2->data.target)
1322 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1324 unsigned char *ip = patch_info->ip.i + code;
1325 gconstpointer target = NULL;
1329 switch (patch_info->type) {
1330 case MONO_PATCH_INFO_BB:
1332 * FIXME: This could be hit for methods without a prolog. Should use -1
1333 * but too much code depends on a 0 initial value.
1335 //g_assert (patch_info->data.bb->native_offset);
1336 target = patch_info->data.bb->native_offset + code;
1338 case MONO_PATCH_INFO_ABS:
1339 target = patch_info->data.target;
1341 case MONO_PATCH_INFO_LABEL:
1342 target = patch_info->data.inst->inst_c0 + code;
1344 case MONO_PATCH_INFO_IP:
1347 case MONO_PATCH_INFO_METHOD_REL:
1348 target = code + patch_info->data.offset;
1350 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1351 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1353 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1354 g_assert_not_reached ();
1356 target = mono_icall_get_wrapper (mi);
1359 case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
1360 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1362 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1363 g_assert_not_reached ();
1368 case MONO_PATCH_INFO_METHOD_JUMP:
1369 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1370 if (!mono_error_ok (error))
1373 case MONO_PATCH_INFO_METHOD:
1374 if (patch_info->data.method == method) {
1377 /* get the trampoline to the method from the domain */
1378 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1379 if (!mono_error_ok (error))
1383 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1386 mono_domain_lock (domain);
1387 if (!domain_jit_info (domain)->method_code_hash)
1388 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1389 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1391 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1392 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1394 mono_domain_unlock (domain);
1398 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1399 #if defined(__native_client_codegen__)
1400 target = (gpointer)&__nacl_thread_suspension_needed;
1402 g_assert (mono_threads_is_coop_enabled ());
1403 target = (gpointer)&mono_polling_required;
1406 case MONO_PATCH_INFO_SWITCH: {
1407 gpointer *jump_table;
1409 #if defined(__native_client__) && defined(__native_client_codegen__)
1410 /* This memory will leak, but we don't care if we're */
1411 /* not deleting JIT'd methods anyway */
1412 jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
1414 if (method && method->dynamic) {
1415 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1417 if (mono_aot_only) {
1418 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1420 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1425 for (i = 0; i < patch_info->data.table->table_size; i++) {
1426 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1429 target = jump_table;
1432 case MONO_PATCH_INFO_METHODCONST:
1433 case MONO_PATCH_INFO_CLASS:
1434 case MONO_PATCH_INFO_IMAGE:
1435 case MONO_PATCH_INFO_FIELD:
1436 case MONO_PATCH_INFO_SIGNATURE:
1437 case MONO_PATCH_INFO_AOT_MODULE:
1438 target = patch_info->data.target;
1440 case MONO_PATCH_INFO_IID:
1441 mono_class_init (patch_info->data.klass);
1442 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1444 case MONO_PATCH_INFO_ADJUSTED_IID:
1445 mono_class_init (patch_info->data.klass);
1446 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1448 case MONO_PATCH_INFO_VTABLE:
1449 target = mono_class_vtable (domain, patch_info->data.klass);
1452 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1453 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1455 if (del_tramp->is_virtual)
1456 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1458 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1461 case MONO_PATCH_INFO_SFLDA: {
1462 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1464 if (mono_class_field_is_special_static (patch_info->data.field)) {
1465 gpointer addr = NULL;
1467 mono_domain_lock (domain);
1468 if (domain->special_static_fields)
1469 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1470 mono_domain_unlock (domain);
1476 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1477 /* Done by the generated code */
1481 if (!mono_runtime_class_init_full (vtable, error)) {
1486 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1489 case MONO_PATCH_INFO_RVA: {
1490 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1493 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1494 target = mono_image_rva_map (patch_info->data.token->image, rva);
1497 case MONO_PATCH_INFO_R4:
1498 case MONO_PATCH_INFO_R8:
1499 target = patch_info->data.target;
1501 case MONO_PATCH_INFO_EXC_NAME:
1502 target = patch_info->data.name;
1504 case MONO_PATCH_INFO_LDSTR:
1506 mono_ldstr_checked (domain, patch_info->data.token->image,
1507 mono_metadata_token_index (patch_info->data.token->token), error);
1509 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1511 MonoClass *handle_class;
1513 handle = mono_ldtoken_checked (patch_info->data.token->image,
1514 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1515 if (!mono_error_ok (error))
1517 mono_class_init (handle_class);
1518 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1520 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1521 if (!mono_error_ok (error))
1525 case MONO_PATCH_INFO_LDTOKEN: {
1527 MonoClass *handle_class;
1529 handle = mono_ldtoken_checked (patch_info->data.token->image,
1530 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1531 if (!mono_error_ok (error))
1532 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1533 mono_class_init (handle_class);
1538 case MONO_PATCH_INFO_DECLSEC:
1539 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1541 case MONO_PATCH_INFO_ICALL_ADDR:
1542 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1543 /* run_cctors == 0 -> AOT */
1544 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1545 const char *exc_class;
1546 const char *exc_arg;
1549 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1551 if (mono_aot_only) {
1552 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1555 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));
1561 target = mono_lookup_internal_call (patch_info->data.method);
1563 if (!target && run_cctors)
1564 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1567 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1568 target = mono_thread_interruption_request_flag ();
1570 case MONO_PATCH_INFO_METHOD_RGCTX: {
1571 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1574 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1577 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1578 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1580 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1583 case MONO_PATCH_INFO_BB_OVF:
1584 case MONO_PATCH_INFO_EXC_OVF:
1585 case MONO_PATCH_INFO_GOT_OFFSET:
1586 case MONO_PATCH_INFO_NONE:
1588 case MONO_PATCH_INFO_RGCTX_FETCH: {
1589 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1591 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1594 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1595 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1597 /* AOT, not needed */
1600 target = mono_arch_get_seq_point_info (domain, code);
1603 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1604 int card_table_shift_bits;
1605 gpointer card_table_mask;
1607 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1610 case MONO_PATCH_INFO_GC_NURSERY_START: {
1614 target = mono_gc_get_nursery (&shift_bits, &size);
1617 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1621 mono_gc_get_nursery (&shift_bits, &size);
1623 target = (gpointer)(mgreg_t)shift_bits;
1626 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1627 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1630 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1634 case MONO_PATCH_INFO_LDSTR_LIT: {
1638 len = strlen ((const char *)patch_info->data.target);
1639 s = (char *)mono_domain_alloc0 (domain, len + 1);
1640 memcpy (s, patch_info->data.target, len);
1645 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1646 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1648 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1649 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1651 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1652 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1654 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1655 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1661 g_assert_not_reached ();
1664 return (gpointer)target;
1668 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1670 MonoGenericInst *inst;
1673 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1675 if (context && context->class_inst) {
1676 inst = context->class_inst;
1677 for (i = 0; i < inst->type_argc; ++i) {
1678 MonoType *type = inst->type_argv [i];
1680 if (mini_is_gsharedvt_gparam (type))
1681 gsctx->is_gsharedvt = TRUE;
1684 if (context && context->method_inst) {
1685 inst = context->method_inst;
1687 for (i = 0; i < inst->type_argc; ++i) {
1688 MonoType *type = inst->type_argv [i];
1690 if (mini_is_gsharedvt_gparam (type))
1691 gsctx->is_gsharedvt = TRUE;
1697 * LOCKING: Acquires the jit code hash lock.
1700 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1703 static gboolean inited = FALSE;
1704 static int lookups = 0;
1705 static int failed_lookups = 0;
1707 mono_domain_jit_code_hash_lock (domain);
1708 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1709 if (!ji && shared) {
1710 /* Try generic sharing */
1711 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1712 if (ji && !ji->has_generic_jit_info)
1715 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1716 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1724 mono_domain_jit_code_hash_unlock (domain);
1730 lookup_method (MonoDomain *domain, MonoMethod *method)
1735 ji = mini_lookup_method (domain, method, NULL);
1738 if (!mono_method_is_generic_sharable (method, FALSE))
1740 shared = mini_get_shared_method (method);
1741 ji = mini_lookup_method (domain, method, shared);
1748 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1750 return lookup_method (domain, method);
1754 static FILE* perf_map_file;
1757 mono_enable_jit_map (void)
1759 if (!perf_map_file) {
1761 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1763 perf_map_file = fopen (name, "w");
1768 mono_emit_jit_tramp (void *start, int size, const char *desc)
1771 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1775 mono_emit_jit_map (MonoJitInfo *jinfo)
1777 if (perf_map_file) {
1778 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1779 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1785 mono_jit_map_is_enabled (void)
1787 return perf_map_file != NULL;
1793 no_gsharedvt_in_wrapper (void)
1795 g_assert_not_reached ();
1801 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.
1802 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1803 Dependency management in this case is too complex to justify implementing it.
1805 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1808 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1809 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1810 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1811 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1816 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1817 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1818 int threads_waiting; /* Number of threads waiting on this job */
1819 gboolean has_cond; /* True if @cond was initialized */
1820 gboolean done; /* True if the method finished JIT'ing */
1821 MonoCoopCond cond; /* Cond sleeping threads wait one */
1822 } JitCompilationEntry;
1825 GPtrArray *in_flight_methods; //JitCompilationEntry*
1827 } JitCompilationData;
1829 static JitCompilationData compilation_data;
1830 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1833 mini_jit_init_job_control (void)
1835 mono_coop_mutex_init (&compilation_data.lock);
1836 compilation_data.in_flight_methods = g_ptr_array_new ();
1840 lock_compilation_data (void)
1842 mono_coop_mutex_lock (&compilation_data.lock);
1846 unlock_compilation_data (void)
1848 mono_coop_mutex_unlock (&compilation_data.lock);
1851 static JitCompilationEntry*
1852 find_method (MonoMethod *method, MonoDomain *domain)
1855 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1856 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1857 if (e->method == method && e->domain == domain)
1865 add_current_thread (MonoJitTlsData *jit_tls)
1867 ++jit_tls->active_jit_methods;
1871 unref_jit_entry (JitCompilationEntry *entry)
1874 if (entry->ref_count)
1876 if (entry->has_cond)
1877 mono_coop_cond_destroy (&entry->cond);
1882 * Returns true if this method waited successfully for another thread to JIT it
1885 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1887 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1888 JitCompilationEntry *entry;
1890 static gboolean inited;
1892 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1893 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1894 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1895 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1899 lock_compilation_data ();
1901 if (!(entry = find_method (method, domain))) {
1902 entry = g_new0 (JitCompilationEntry, 1);
1903 entry->method = method;
1904 entry->domain = domain;
1905 entry->compilation_count = entry->ref_count = 1;
1906 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1907 g_assert (find_method (method, domain) == entry);
1908 add_current_thread (jit_tls);
1910 unlock_compilation_data ();
1912 } else if (jit_tls->active_jit_methods > 0) {
1913 //We can't suspend the current thread if it's already JITing a method.
1914 //Dependency management is too compilated and we want to get rid of this anyways.
1915 ++entry->compilation_count;
1916 ++jit_methods_multiple;
1917 ++jit_tls->active_jit_methods;
1919 unlock_compilation_data ();
1922 ++jit_methods_waited;
1925 if (!entry->has_cond) {
1926 mono_coop_cond_init (&entry->cond);
1927 entry->has_cond = TRUE;
1931 ++entry->threads_waiting;
1933 g_assert (entry->has_cond);
1934 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1935 --entry->threads_waiting;
1938 unref_jit_entry (entry);
1939 unlock_compilation_data ();
1942 ++jit_spurious_wakeups;
1949 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1951 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1953 lock_compilation_data ();
1955 g_assert (jit_tls->active_jit_methods > 0);
1956 --jit_tls->active_jit_methods;
1958 JitCompilationEntry *entry = find_method (method, target_domain);
1959 g_assert (entry); // It would be weird to fail
1962 if (entry->threads_waiting) {
1963 g_assert (entry->has_cond);
1964 mono_coop_cond_broadcast (&entry->cond);
1967 if (--entry->compilation_count == 0) {
1968 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1969 unref_jit_entry (entry);
1972 unlock_compilation_data ();
1977 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1979 MonoDomain *target_domain, *domain = mono_domain_get ();
1981 gpointer code = NULL, p;
1983 MonoJitICallInfo *callinfo = NULL;
1984 WrapperInfo *winfo = NULL;
1988 #ifdef ENABLE_INTERPRETER
1989 if (mono_use_interpreter && !jit_only) {
1990 code = mono_interp_create_method_pointer (method, error);
1997 /* Should be handled by the caller */
1998 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2001 * ICALL wrappers are handled specially, since there is only one copy of them
2002 * shared by all appdomains.
2004 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2005 winfo = mono_marshal_get_wrapper_info (method);
2006 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2007 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2008 g_assert (callinfo);
2010 /* Must be domain neutral since there is only one copy */
2011 opt |= MONO_OPT_SHARED;
2013 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2014 opt &= ~MONO_OPT_SHARED;
2017 if (opt & MONO_OPT_SHARED)
2018 target_domain = mono_get_root_domain ();
2020 target_domain = domain;
2022 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2023 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2026 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2027 MonoGenericContext *ctx = NULL;
2028 if (method->is_inflated)
2029 ctx = mono_method_get_context (method);
2030 method = info->d.synchronized_inner.method;
2032 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2033 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2039 info = lookup_method (target_domain, method);
2041 /* We can't use a domain specific method in another domain */
2042 if (! ((domain != target_domain) && !info->domain_neutral)) {
2045 mono_jit_stats.methods_lookups++;
2046 vtable = mono_class_vtable_full (domain, method->klass, error);
2050 if (!mono_runtime_class_init_full (vtable, error))
2052 return mono_create_ftnptr (target_domain, info->code_start);
2056 #ifdef MONO_USE_AOT_COMPILER
2057 if (opt & MONO_OPT_AOT) {
2058 MonoDomain *domain = mono_domain_get ();
2060 mono_class_init (method->klass);
2062 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2065 if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
2067 * The suspend code needs to be able to lookup these methods by ip in async context,
2068 * so preload their jit info.
2070 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2075 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2076 * This is not a problem, since it will be initialized when the method is first
2077 * called by init_method ().
2079 if (!mono_llvm_only) {
2080 vtable = mono_class_vtable (domain, method->klass);
2082 if (!mono_runtime_class_init_full (vtable, error))
2091 if (!code && mono_llvm_only) {
2092 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2093 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2095 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2097 * These wrappers are only created for signatures which are in the program, but
2098 * sometimes we load methods too eagerly and have to create them even if they
2099 * will never be called.
2101 return no_gsharedvt_in_wrapper;
2107 if (wait_or_register_method_to_compile (method, target_domain))
2109 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2110 unregister_method_for_compile (method, target_domain);
2112 if (!mono_error_ok (error))
2115 if (!code && mono_llvm_only) {
2116 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2117 g_assert_not_reached ();
2123 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2127 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2129 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2133 p = mono_create_ftnptr (target_domain, code);
2136 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2137 mono_loader_lock ();
2139 if (!callinfo->wrapper) {
2140 callinfo->wrapper = p;
2141 mono_register_jit_icall_wrapper (callinfo, p);
2144 mono_loader_unlock ();
2151 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2155 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2160 * mono_jit_compile_method_jit_only:
2162 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2165 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2169 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2173 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2175 invalidated_delegate_trampoline (char *desc)
2177 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2178 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2184 * mono_jit_free_method:
2186 * Free all memory allocated by the JIT for METHOD.
2189 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2191 MonoJitDynamicMethodInfo *ji;
2192 gboolean destroy = TRUE;
2193 GHashTableIter iter;
2194 MonoJumpList *jlist;
2196 g_assert (method->dynamic);
2198 mono_domain_lock (domain);
2199 ji = mono_dynamic_code_hash_lookup (domain, method);
2200 mono_domain_unlock (domain);
2205 mono_debug_remove_method (method, domain);
2206 mono_lldb_remove_method (domain, method, ji);
2208 mono_domain_lock (domain);
2209 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2210 mono_domain_jit_code_hash_lock (domain);
2211 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2212 mono_domain_jit_code_hash_unlock (domain);
2213 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2215 /* requires the domain lock - took above */
2216 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2218 /* Remove jump targets in this method */
2219 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2220 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2221 GSList *tmp, *remove;
2224 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2225 guint8 *ip = (guint8 *)tmp->data;
2227 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2228 remove = g_slist_prepend (remove, tmp);
2230 for (tmp = remove; tmp; tmp = tmp->next) {
2231 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2233 g_slist_free (remove);
2235 mono_domain_unlock (domain);
2237 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2238 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2240 * Instead of freeing the code, change it to call an error routine
2241 * so people can fix their code.
2243 char *type = mono_type_full_name (&method->klass->byval_arg);
2244 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2247 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2253 * This needs to be done before freeing code_mp, since the code address is the
2254 * key in the table, so if we free the code_mp first, another thread can grab the
2255 * same code address and replace our entry in the table.
2257 mono_jit_info_table_remove (domain, ji->ji);
2260 mono_code_manager_destroy (ji->code_mp);
2265 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2267 MonoDomain *target_domain;
2270 if (default_opt & MONO_OPT_SHARED)
2271 target_domain = mono_get_root_domain ();
2273 target_domain = domain;
2275 info = lookup_method (target_domain, method);
2277 /* We can't use a domain specific method in another domain */
2278 if (! ((domain != target_domain) && !info->domain_neutral)) {
2279 mono_jit_stats.methods_lookups++;
2282 return info->code_start;
2291 static guint32 bisect_opt = 0;
2292 static GHashTable *bisect_methods_hash = NULL;
2295 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2298 char method_name [2048];
2301 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2302 g_assert (bisect_methods_hash);
2304 file = fopen (method_list_filename, "r");
2307 while (fgets (method_name, sizeof (method_name), file)) {
2308 size_t len = strlen (method_name);
2310 g_assert (method_name [len - 1] == '\n');
2311 method_name [len - 1] = 0;
2312 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2314 g_assert (feof (file));
2317 gboolean mono_do_single_method_regression = FALSE;
2318 guint32 mono_single_method_regression_opt = 0;
2319 MonoMethod *mono_current_single_method;
2320 GSList *mono_single_method_list;
2321 GHashTable *mono_single_method_hash;
2324 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2328 if (bisect_methods_hash) {
2329 char *name = mono_method_full_name (method, TRUE);
2330 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2333 return default_opt | bisect_opt;
2335 if (!mono_do_single_method_regression)
2337 if (!mono_current_single_method) {
2338 if (!mono_single_method_hash)
2339 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2340 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2341 g_hash_table_insert (mono_single_method_hash, method, method);
2342 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2346 if (method == mono_current_single_method)
2347 return mono_single_method_regression_opt;
2352 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2354 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2359 gpointer compiled_method;
2360 gpointer runtime_invoke;
2362 MonoDynCallInfo *dyn_call_info;
2363 MonoClass *ret_box_class;
2364 MonoMethodSignature *sig;
2365 gboolean gsharedvt_invoke;
2366 gpointer *wrapper_arg;
2367 } RuntimeInvokeInfo;
2369 static RuntimeInvokeInfo*
2370 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2373 RuntimeInvokeInfo *info;
2375 info = g_new0 (RuntimeInvokeInfo, 1);
2376 info->compiled_method = compiled_method;
2377 if (mono_llvm_only && method->string_ctor)
2378 info->sig = mono_marshal_get_string_ctor_signature (method);
2380 info->sig = mono_method_signature (method);
2382 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2383 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2384 if (!mono_error_ok (error))
2386 g_assert (info->vtable);
2388 MonoMethodSignature *sig = info->sig;
2392 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2393 * in full-aot mode, so we use a slower, but more generic wrapper if
2394 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2396 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2397 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2398 gboolean supported = TRUE;
2401 if (method->string_ctor)
2402 sig = mono_marshal_get_string_ctor_signature (method);
2404 for (i = 0; i < sig->param_count; ++i) {
2405 MonoType *t = sig->params [i];
2407 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2411 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2415 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2419 ret_type = sig->ret;
2420 switch (ret_type->type) {
2421 case MONO_TYPE_VOID:
2433 case MONO_TYPE_BOOLEAN:
2434 case MONO_TYPE_CHAR:
2437 info->ret_box_class = mono_class_from_mono_type (ret_type);
2440 info->ret_box_class = mono_defaults.int_class;
2442 case MONO_TYPE_STRING:
2443 case MONO_TYPE_CLASS:
2444 case MONO_TYPE_ARRAY:
2445 case MONO_TYPE_SZARRAY:
2446 case MONO_TYPE_OBJECT:
2448 case MONO_TYPE_GENERICINST:
2449 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2450 info->ret_box_class = mono_class_from_mono_type (ret_type);
2452 case MONO_TYPE_VALUETYPE:
2453 info->ret_box_class = mono_class_from_mono_type (ret_type);
2456 g_assert_not_reached ();
2460 if (!info->dyn_call_info) {
2461 if (mono_llvm_only) {
2462 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2463 g_assert_not_reached ();
2465 info->gsharedvt_invoke = TRUE;
2466 if (!callee_gsharedvt) {
2467 /* Invoke a gsharedvt out wrapper instead */
2468 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2469 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2471 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2472 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2474 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2475 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2476 g_free (wrapper_sig);
2478 info->compiled_method = mono_jit_compile_method (wrapper, error);
2479 if (!mono_error_ok (error)) {
2484 /* Gsharedvt methods can be invoked the same way */
2485 /* The out wrapper has the same signature as the compiled gsharedvt method */
2486 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2488 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2490 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2491 g_free (wrapper_sig);
2494 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2495 if (!mono_error_ok (error)) {
2505 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2507 MonoMethodSignature *sig = info->sig;
2508 MonoDomain *domain = mono_domain_get ();
2509 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2511 gpointer retval_ptr;
2512 guint8 retval [256];
2513 gpointer *param_refs;
2518 g_assert (info->gsharedvt_invoke);
2521 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2522 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2523 * signatures, so we only have to generate runtime invoke wrappers for these
2525 * This code also handles invocation of gsharedvt methods directly, no
2526 * out wrappers are used in that case.
2528 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2529 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2532 * The runtime invoke wrappers expects pointers to primitive types, so have to
2536 args [pindex ++] = &obj;
2537 if (sig->ret->type != MONO_TYPE_VOID) {
2538 retval_ptr = (gpointer)&retval;
2539 args [pindex ++] = &retval_ptr;
2541 for (i = 0; i < sig->param_count; ++i) {
2542 MonoType *t = sig->params [i];
2544 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2545 MonoClass *klass = mono_class_from_mono_type (t);
2546 guint8 *nullable_buf;
2549 size = mono_class_value_size (klass, NULL);
2550 nullable_buf = g_alloca (size);
2551 g_assert (nullable_buf);
2553 /* The argument pointed to by params [i] is either a boxed vtype or null */
2554 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2555 params [i] = nullable_buf;
2558 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2559 param_refs [i] = params [i];
2560 params [i] = &(param_refs [i]);
2562 args [pindex ++] = ¶ms [i];
2564 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2565 args [pindex ++] = &info->wrapper_arg;
2567 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2569 runtime_invoke (NULL, args, exc, info->compiled_method);
2573 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2574 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2576 return *(MonoObject**)retval;
2580 * mono_jit_runtime_invoke:
2581 * \param method: the method to invoke
2582 * \param obj: this pointer
2583 * \param params: array of parameter values.
2584 * \param exc: Set to the exception raised in the managed method.
2585 * \param error: error or caught exception object
2586 * If \p exc is NULL, \p error is thrown instead.
2587 * If coop is enabled, \p exc argument is ignored -
2588 * all exceptions are caught and propagated through \p error
2591 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2593 MonoMethod *invoke, *callee;
2594 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2595 MonoDomain *domain = mono_domain_get ();
2596 MonoJitDomainInfo *domain_info;
2597 RuntimeInvokeInfo *info, *info2;
2598 MonoJitInfo *ji = NULL;
2599 gboolean callee_gsharedvt = FALSE;
2601 #ifdef ENABLE_INTERPRETER
2602 if (mono_use_interpreter)
2603 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2608 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2609 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2613 domain_info = domain_jit_info (domain);
2615 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2618 if (mono_security_core_clr_enabled ()) {
2620 * This might be redundant since mono_class_vtable () already does this,
2621 * but keep it just in case for moonlight.
2623 mono_class_setup_vtable (method->klass);
2624 if (mono_class_has_failure (method->klass)) {
2625 mono_error_set_for_class_failure (error, method->klass);
2627 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2632 gpointer compiled_method;
2635 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2636 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2638 * Array Get/Set/Address methods. The JIT implements them using inline code
2639 * inside the runtime invoke wrappers, so no need to compile them.
2641 if (mono_aot_only) {
2643 * Call a wrapper, since the runtime invoke wrapper was not generated.
2645 MonoMethod *wrapper;
2647 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2648 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2656 compiled_method = mono_jit_compile_method (callee, error);
2657 if (!compiled_method) {
2658 g_assert (!mono_error_ok (error));
2662 if (mono_llvm_only) {
2663 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2664 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2665 if (callee_gsharedvt)
2666 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2669 if (!callee_gsharedvt)
2670 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2672 compiled_method = NULL;
2675 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2676 if (!mono_error_ok (error))
2679 mono_domain_lock (domain);
2680 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2681 mono_domain_unlock (domain);
2689 * We need this here because mono_marshal_get_runtime_invoke can place
2690 * the helper method in System.Object and not the target class.
2692 if (!mono_runtime_class_init_full (info->vtable, error)) {
2694 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2698 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2699 we always catch the exception and propagate it through the MonoError */
2700 gboolean catchExcInMonoError =
2701 (exc == NULL) && mono_threads_is_coop_enabled ();
2702 MonoObject *invoke_exc = NULL;
2703 if (catchExcInMonoError)
2706 /* The wrappers expect this to be initialized to NULL */
2710 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2711 if (info->dyn_call_info) {
2712 MonoMethodSignature *sig = mono_method_signature (method);
2714 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2717 guint8 retval [256];
2719 if (!dyn_runtime_invoke) {
2720 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2721 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2722 if (!mono_error_ok (error))
2726 /* Convert the arguments to the format expected by start_dyn_call () */
2727 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2730 args [pindex ++] = &obj;
2731 for (i = 0; i < sig->param_count; ++i) {
2732 MonoType *t = sig->params [i];
2735 args [pindex ++] = ¶ms [i];
2736 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2737 args [pindex ++] = ¶ms [i];
2739 args [pindex ++] = params [i];
2743 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2745 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2747 dyn_runtime_invoke (buf, exc, info->compiled_method);
2748 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2750 if (catchExcInMonoError && *exc != NULL) {
2751 mono_error_set_exception_instance (error, (MonoException*) *exc);
2755 if (info->ret_box_class)
2756 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2758 return *(MonoObject**)retval;
2764 if (mono_llvm_only) {
2765 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2769 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2771 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2773 if (catchExcInMonoError && *exc != NULL)
2774 mono_error_set_exception_instance (error, (MonoException*) *exc);
2783 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2786 * mini_llvmonly_initial_imt_tramp:
2788 * This function is called the first time a call is made through an IMT trampoline.
2789 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2792 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2794 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2799 mono_vtable_build_imt_slot (info->vtable, info->slot);
2801 imt = (gpointer*)info->vtable;
2802 imt -= MONO_IMT_SIZE;
2804 /* Return what the real IMT trampoline returns */
2805 ftndesc = imt [info->slot];
2808 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2809 /* Happens when the imt slot contains only a generic virtual method */
2811 return func ((gpointer *)ftndesc [1], imt_method);
2814 /* This is called indirectly through an imt slot. */
2816 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2820 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2821 while (arg [i] && arg [i] != imt_method)
2828 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2830 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2832 //g_assert (arg [0] == imt_method);
2837 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2839 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2840 if (arg [0] == imt_method)
2847 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2849 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2850 if (arg [0] == imt_method)
2852 else if (arg [2] == imt_method)
2859 * A version of the imt trampoline used for generic virtual/variant iface methods.
2860 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2861 * in the search table. The original JIT code had a 'fallback' trampoline it could
2862 * call, but we can't do that, so we just return NULL, and the compiled code
2866 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2870 while (arg [i] && arg [i] != imt_method)
2879 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2883 int i, index, real_count;
2884 gboolean virtual_generic = FALSE;
2887 * Create an array which is passed to the imt trampoline functions.
2888 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2892 for (i = 0; i < count; ++i) {
2893 MonoIMTCheckItem *item = imt_entries [i];
2895 if (item->is_equals)
2897 if (item->has_target_code)
2898 virtual_generic = TRUE;
2902 * Initialize all vtable entries reachable from this imt slot, so the compiled
2903 * code doesn't have to check it.
2905 for (i = 0; i < count; ++i) {
2906 MonoIMTCheckItem *item = imt_entries [i];
2909 if (!item->is_equals || item->has_target_code)
2911 vt_slot = item->value.vtable_slot;
2912 mono_init_vtable_slot (vtable, vt_slot);
2915 /* Save the entries into an array */
2916 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2918 for (i = 0; i < count; ++i) {
2919 MonoIMTCheckItem *item = imt_entries [i];
2921 if (!item->is_equals)
2924 g_assert (item->key);
2925 buf [(index * 2)] = item->key;
2926 if (item->has_target_code)
2927 buf [(index * 2) + 1] = item->value.target_code;
2929 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2932 buf [(index * 2)] = NULL;
2933 buf [(index * 2) + 1] = fail_tramp;
2936 * Return a function descriptor for a C function with 'buf' as its argument.
2937 * It will by called by JITted code.
2939 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2940 switch (real_count) {
2942 res [0] = mono_llvmonly_imt_tramp_1;
2945 res [0] = mono_llvmonly_imt_tramp_2;
2948 res [0] = mono_llvmonly_imt_tramp_3;
2951 res [0] = mono_llvmonly_imt_tramp;
2954 if (virtual_generic || fail_tramp)
2955 res [0] = mono_llvmonly_fallback_imt_tramp;
2961 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2963 MonoException *exc = NULL;
2965 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2966 MONO_SIG_HANDLER_GET_CONTEXT;
2968 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2970 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2972 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2973 if (mono_arch_is_int_overflow (ctx, info))
2975 * The spec says this throws ArithmeticException, but MS throws the derived
2976 * OverflowException.
2978 exc = mono_get_exception_overflow ();
2980 exc = mono_get_exception_divide_by_zero ();
2982 exc = mono_get_exception_divide_by_zero ();
2986 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
2989 mono_handle_native_crash ("SIGFPE", ctx, info);
2990 if (mono_do_crash_chaining) {
2991 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
2996 mono_arch_handle_exception (ctx, exc);
2999 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3002 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3004 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3005 MONO_SIG_HANDLER_GET_CONTEXT;
3007 if (mono_runtime_get_no_exec ())
3011 mono_handle_native_crash ("SIGILL", ctx, info);
3012 if (mono_do_crash_chaining) {
3013 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3017 g_assert_not_reached ();
3020 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3021 #define HAVE_SIG_INFO
3024 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3027 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3028 gpointer fault_addr = NULL;
3029 #ifdef HAVE_SIG_INFO
3030 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3034 MONO_SIG_HANDLER_GET_CONTEXT;
3036 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3037 if (mono_arch_is_single_step_event (info, ctx)) {
3038 mono_debugger_agent_single_step_event (ctx);
3040 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3041 mono_debugger_agent_breakpoint_hit (ctx);
3046 #if defined(HAVE_SIG_INFO)
3047 #if !defined(HOST_WIN32)
3048 fault_addr = info->si_addr;
3049 if (mono_aot_is_pagefault (info->si_addr)) {
3050 mono_aot_handle_pagefault (info->si_addr);
3055 /* The thread might no be registered with the runtime */
3056 if (!mono_domain_get () || !jit_tls) {
3057 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3059 mono_handle_native_crash ("SIGSEGV", ctx, info);
3060 if (mono_do_crash_chaining) {
3061 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3067 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3069 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3070 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3073 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3074 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3075 fault_addr = info->si_addr;
3076 if (fault_addr == NULL) {
3079 mono_sigctx_to_monoctx (ctx, &mctx);
3081 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3085 if (jit_tls->stack_size &&
3086 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3088 * The hard-guard page has been hit: there is not much we can do anymore
3089 * Print a hopefully clear message and abort.
3091 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3092 g_assert_not_reached ();
3094 /* The original handler might not like that it is executed on an altstack... */
3095 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3098 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3103 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3106 mono_handle_native_crash ("SIGSEGV", ctx, info);
3108 if (mono_do_crash_chaining) {
3109 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3114 mono_arch_handle_exception (ctx, NULL);
3118 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3121 MONO_SIG_HANDLER_GET_CONTEXT;
3123 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3125 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3127 mono_arch_handle_exception (ctx, exc);
3129 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3132 #ifndef DISABLE_REMOTING
3133 /* mono_jit_create_remoting_trampoline:
3134 * @method: pointer to the method info
3136 * Creates a trampoline which calls the remoting functions. This
3137 * is used in the vtable of transparent proxies.
3139 * Returns: a pointer to the newly created code
3142 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3145 guint8 *addr = NULL;
3149 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3150 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3154 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3155 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3156 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3159 addr = (guint8 *)mono_compile_method_checked (nm, error);
3160 return_val_if_nok (error, NULL);
3161 return mono_get_addr_from_ftnptr (addr);
3165 static G_GNUC_UNUSED void
3166 no_imt_trampoline (void)
3168 g_assert_not_reached ();
3171 static G_GNUC_UNUSED void
3172 no_vcall_trampoline (void)
3174 g_assert_not_reached ();
3177 static gpointer *vtable_trampolines;
3178 static int vtable_trampolines_size;
3181 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3183 int index = slot_index + MONO_IMT_SIZE;
3185 if (mono_llvm_only) {
3186 if (slot_index < 0) {
3187 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3188 // FIXME: Memory management
3189 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3190 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3193 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3195 mono_memory_barrier ();
3202 g_assert (slot_index >= - MONO_IMT_SIZE);
3203 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3205 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3209 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3210 while (new_size <= index)
3212 new_table = g_new0 (gpointer, new_size);
3214 if (vtable_trampolines)
3215 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3216 g_free (vtable_trampolines);
3217 mono_memory_barrier ();
3218 vtable_trampolines = (void **)new_table;
3219 vtable_trampolines_size = new_size;
3224 if (!vtable_trampolines [index])
3225 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3226 return vtable_trampolines [index];
3230 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3232 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3236 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3241 gpointer *imt = (gpointer*)vt;
3242 imt -= MONO_IMT_SIZE;
3244 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3248 is_callee_gsharedvt_variable (gpointer addr)
3251 gboolean callee_gsharedvt;
3253 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3255 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3256 if (callee_gsharedvt)
3257 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3258 return callee_gsharedvt;
3262 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3264 gpointer arg = NULL;
3266 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3267 arg = mini_method_get_rgctx (method);
3270 * Avoid adding gsharedvt in wrappers since they might not exist if
3271 * this delegate is called through a gsharedvt delegate invoke wrapper.
3272 * Instead, encode that the method is gsharedvt in del->extra_arg,
3273 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3275 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3276 g_assert ((((mgreg_t)arg) & 1) == 0);
3277 arg = (gpointer)(((mgreg_t)arg) | 1);
3283 mini_init_delegate (MonoDelegate *del)
3286 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3287 #ifdef ENABLE_INTERPRETER
3288 if (mono_use_interpreter)
3289 mono_interp_init_delegate (del);
3294 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3298 abs_offset = offset;
3300 abs_offset = - abs_offset;
3301 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3305 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3307 gboolean is_virtual_generic, is_interface, load_imt_reg;
3310 static guint8 **cache = NULL;
3311 static int cache_size = 0;
3316 if (MONO_TYPE_ISSTRUCT (sig->ret))
3319 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3320 is_interface = mono_class_is_interface (method->klass);
3321 load_imt_reg = is_virtual_generic || is_interface;
3324 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3326 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3328 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3329 g_assert (idx >= 0);
3331 /* Resize the cache to idx + 1 */
3332 if (cache_size < idx + 1) {
3334 if (cache_size < idx + 1) {
3336 int new_cache_size = idx + 1;
3338 new_cache = g_new0 (guint8*, new_cache_size);
3340 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3343 mono_memory_barrier ();
3345 cache_size = new_cache_size;
3353 /* FIXME Support more cases */
3354 if (mono_aot_only) {
3355 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3356 g_assert (cache [idx]);
3358 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3364 * mini_parse_debug_option:
3365 * @option: The option to parse.
3367 * Parses debug options for the mono runtime. The options are the same as for
3368 * the MONO_DEBUG environment variable.
3372 mini_parse_debug_option (const char *option)
3374 if (!strcmp (option, "handle-sigint"))
3375 debug_options.handle_sigint = TRUE;
3376 else if (!strcmp (option, "keep-delegates"))
3377 debug_options.keep_delegates = TRUE;
3378 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3379 debug_options.reverse_pinvoke_exceptions = TRUE;
3380 else if (!strcmp (option, "collect-pagefault-stats"))
3381 debug_options.collect_pagefault_stats = TRUE;
3382 else if (!strcmp (option, "break-on-unverified"))
3383 debug_options.break_on_unverified = TRUE;
3384 else if (!strcmp (option, "no-gdb-backtrace"))
3385 debug_options.no_gdb_backtrace = TRUE;
3386 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3387 debug_options.suspend_on_native_crash = TRUE;
3388 else if (!strcmp (option, "suspend-on-exception"))
3389 debug_options.suspend_on_exception = TRUE;
3390 else if (!strcmp (option, "suspend-on-unhandled"))
3391 debug_options.suspend_on_unhandled = TRUE;
3392 else if (!strcmp (option, "dont-free-domains"))
3393 mono_dont_free_domains = TRUE;
3394 else if (!strcmp (option, "dyn-runtime-invoke"))
3395 debug_options.dyn_runtime_invoke = TRUE;
3396 else if (!strcmp (option, "gdb"))
3397 debug_options.gdb = TRUE;
3398 else if (!strcmp (option, "lldb"))
3399 debug_options.lldb = TRUE;
3400 else if (!strcmp (option, "explicit-null-checks"))
3401 debug_options.explicit_null_checks = TRUE;
3402 else if (!strcmp (option, "gen-seq-points"))
3403 debug_options.gen_sdb_seq_points = TRUE;
3404 else if (!strcmp (option, "gen-compact-seq-points"))
3405 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3406 else if (!strcmp (option, "no-compact-seq-points"))
3407 debug_options.no_seq_points_compact_data = TRUE;
3408 else if (!strcmp (option, "single-imm-size"))
3409 debug_options.single_imm_size = TRUE;
3410 else if (!strcmp (option, "init-stacks"))
3411 debug_options.init_stacks = TRUE;
3412 else if (!strcmp (option, "casts"))
3413 debug_options.better_cast_details = TRUE;
3414 else if (!strcmp (option, "soft-breakpoints"))
3415 debug_options.soft_breakpoints = TRUE;
3416 else if (!strcmp (option, "check-pinvoke-callconv"))
3417 debug_options.check_pinvoke_callconv = TRUE;
3418 else if (!strcmp (option, "use-fallback-tls"))
3419 debug_options.use_fallback_tls = TRUE;
3420 else if (!strcmp (option, "debug-domain-unload"))
3421 mono_enable_debug_domain_unload (TRUE);
3422 else if (!strcmp (option, "partial-sharing"))
3423 mono_set_partial_sharing_supported (TRUE);
3424 else if (!strcmp (option, "align-small-structs"))
3425 mono_align_small_structs = TRUE;
3426 else if (!strcmp (option, "native-debugger-break"))
3427 debug_options.native_debugger_break = TRUE;
3428 else if (!strcmp (option, "disable_omit_fp"))
3429 debug_options.disable_omit_fp = TRUE;
3437 mini_parse_debug_options (void)
3439 char *options = g_getenv ("MONO_DEBUG");
3440 gchar **args, **ptr;
3445 args = g_strsplit (options, ",", -1);
3448 for (ptr = args; ptr && *ptr; ptr++) {
3449 const char *arg = *ptr;
3451 if (!mini_parse_debug_option (arg)) {
3452 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3453 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");
3462 mini_get_debug_options (void)
3464 return &debug_options;
3468 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3470 #if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3473 gpointer* desc = NULL;
3475 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3478 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
3482 # elif defined(__ppc64__) || defined(__powerpc64__)
3484 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3490 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3496 mini_get_addr_from_ftnptr (gpointer descr)
3498 #if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3499 return *(gpointer*)descr;
3506 register_jit_stats (void)
3508 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3509 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3510 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3511 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3512 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3513 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3514 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);
3515 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3516 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3517 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3518 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3519 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3520 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3521 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3522 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3523 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3524 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3525 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3526 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3527 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3528 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3529 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3530 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3531 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3532 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3533 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3534 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3535 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3536 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3537 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3538 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3539 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3540 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3541 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3542 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3543 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3544 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3545 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3546 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3547 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3548 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3549 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3550 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3551 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3552 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3553 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3554 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3555 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3556 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3557 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3558 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3559 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3560 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3561 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3562 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3563 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3564 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3565 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3566 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3567 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3568 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3571 static void runtime_invoke_info_free (gpointer value);
3574 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3576 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3577 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3579 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3583 class_method_pair_hash (gconstpointer data)
3585 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3587 return (gsize)pair->klass ^ (gsize)pair->method;
3591 mini_create_jit_domain_info (MonoDomain *domain)
3593 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3595 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3596 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3597 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3598 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3599 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3600 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3601 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3602 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3603 mono_jit_code_hash_init (&info->interp_code_hash);
3605 domain->runtime_info = info;
3609 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3611 MonoJumpList *jlist = (MonoJumpList *)value;
3612 g_slist_free (jlist->list);
3616 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3618 GSList *list = (GSList *)value;
3619 g_slist_free (list);
3623 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3625 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3626 mono_code_manager_destroy (di->code_mp);
3631 runtime_invoke_info_free (gpointer value)
3633 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3635 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3636 if (info->dyn_call_info)
3637 mono_arch_dyn_call_free (info->dyn_call_info);
3643 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3645 g_slist_free (value);
3649 mini_free_jit_domain_info (MonoDomain *domain)
3651 MonoJitDomainInfo *info = domain_jit_info (domain);
3653 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3654 g_hash_table_destroy (info->jump_target_hash);
3655 if (info->jump_target_got_slot_hash) {
3656 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3657 g_hash_table_destroy (info->jump_target_got_slot_hash);
3659 if (info->dynamic_code_hash) {
3660 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3661 g_hash_table_destroy (info->dynamic_code_hash);
3663 if (info->method_code_hash)
3664 g_hash_table_destroy (info->method_code_hash);
3665 g_hash_table_destroy (info->jump_trampoline_hash);
3666 g_hash_table_destroy (info->jit_trampoline_hash);
3667 g_hash_table_destroy (info->delegate_trampoline_hash);
3668 if (info->static_rgctx_trampoline_hash)
3669 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3670 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3671 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3672 g_hash_table_destroy (info->seq_points);
3673 g_hash_table_destroy (info->arch_seq_points);
3674 if (info->agent_info)
3675 mono_debugger_agent_free_domain_info (domain);
3676 if (info->gsharedvt_arg_tramp_hash)
3677 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3678 if (info->llvm_jit_callees) {
3679 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3680 g_hash_table_destroy (info->llvm_jit_callees);
3682 mono_internal_hash_table_destroy (&info->interp_code_hash);
3684 mono_llvm_free_domain_info (domain);
3687 g_free (domain->runtime_info);
3688 domain->runtime_info = NULL;
3691 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3694 code_manager_chunk_new (void *chunk, int size)
3696 mono_arch_code_chunk_new (chunk, size);
3700 code_manager_chunk_destroy (void *chunk)
3702 mono_arch_code_chunk_destroy (chunk);
3709 llvm_init_inner (void)
3711 if (!mono_llvm_load (NULL))
3722 * Load and initialize LLVM support.
3723 * Return TRUE on success.
3726 mini_llvm_init (void)
3729 static gboolean llvm_inited;
3730 static gboolean init_result;
3732 mono_loader_lock_if_inited ();
3734 init_result = llvm_init_inner ();
3737 mono_loader_unlock_if_inited ();
3745 mini_profiler_enable_with_options (const char* profile_options)
3747 mini_enable_profiler = TRUE;
3748 mini_profiler_options = g_strdup (profile_options);
3752 mini_init (const char *filename, const char *runtime_version)
3756 MonoRuntimeCallbacks callbacks;
3757 MonoThreadInfoRuntimeCallbacks ticallbacks;
3758 MonoCodeManagerCallbacks code_manager_callbacks;
3760 MONO_VES_INIT_BEGIN ();
3762 CHECKED_MONO_INIT ();
3764 #if defined(__linux__) && !defined(__native_client__)
3765 if (access ("/proc/self/maps", F_OK) != 0) {
3766 g_print ("Mono requires /proc to be mounted.\n");
3771 #ifdef ENABLE_INTERPRETER
3772 mono_interp_init ();
3775 mono_os_mutex_init_recursive (&jit_mutex);
3777 mono_cross_helpers_run ();
3779 mono_counters_init ();
3783 mini_jit_init_job_control ();
3785 /* Happens when using the embedding interface */
3786 if (!default_opt_set)
3787 default_opt = mono_parse_default_optimizations (NULL);
3789 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3791 mono_set_generic_sharing_vt_supported (TRUE);
3794 mono_set_generic_sharing_vt_supported (TRUE);
3797 mono_tls_init_runtime_keys ();
3799 if (!global_codeman)
3800 global_codeman = mono_code_manager_new ();
3802 memset (&callbacks, 0, sizeof (callbacks));
3803 callbacks.create_ftnptr = mini_create_ftnptr;
3804 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3805 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3806 callbacks.set_cast_details = mono_set_cast_details;
3807 callbacks.debug_log = mono_debugger_agent_debug_log;
3808 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3809 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3810 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3811 callbacks.imt_entry_inited = mini_imt_entry_inited;
3812 callbacks.init_delegate = mini_init_delegate;
3813 #define JIT_INVOKE_WORKS
3814 #ifdef JIT_INVOKE_WORKS
3815 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3817 #define JIT_TRAMPOLINES_WORK
3818 #ifdef JIT_TRAMPOLINES_WORK
3819 callbacks.compile_method = mono_jit_compile_method;
3820 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3821 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3822 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3823 callbacks.free_method = mono_jit_free_method;
3824 #ifndef DISABLE_REMOTING
3825 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3829 mono_install_callbacks (&callbacks);
3831 memset (&ticallbacks, 0, sizeof (ticallbacks));
3832 ticallbacks.setup_async_callback = mono_setup_async_callback;
3833 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3834 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3835 ticallbacks.thread_state_init = mono_thread_state_init;
3838 mono_w32handle_init ();
3841 mono_threads_runtime_init (&ticallbacks);
3843 if (g_hasenv ("MONO_DEBUG")) {
3844 mini_parse_debug_options ();
3847 mono_code_manager_init ();
3849 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3850 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3851 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3852 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3854 mono_code_manager_install_callbacks (&code_manager_callbacks);
3858 mono_arch_cpu_init ();
3862 mono_unwind_init ();
3864 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3865 mono_lldb_init ("");
3866 mono_dont_free_domains = TRUE;
3869 #ifdef XDEBUG_ENABLED
3870 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3872 mono_xdebug_init (mono_xdebug);
3873 g_free (mono_xdebug);
3874 /* So methods for multiple domains don't have the same address */
3875 mono_dont_free_domains = TRUE;
3876 mono_using_xdebug = TRUE;
3877 } else if (mini_get_debug_options ()->gdb) {
3878 mono_xdebug_init ((char*)"gdb");
3879 mono_dont_free_domains = TRUE;
3880 mono_using_xdebug = TRUE;
3885 if (mono_use_llvm) {
3886 if (!mono_llvm_load (NULL)) {
3887 mono_use_llvm = FALSE;
3888 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3895 mono_trampolines_init ();
3897 if (default_opt & MONO_OPT_AOT)
3900 mono_debugger_agent_init ();
3902 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3903 mono_set_generic_sharing_supported (TRUE);
3906 mono_threads_signals_init ();
3908 #ifndef MONO_CROSS_COMPILE
3909 mono_runtime_install_handlers ();
3911 mono_threads_install_cleanup (mini_thread_cleanup);
3913 #ifdef JIT_TRAMPOLINES_WORK
3914 mono_install_create_domain_hook (mini_create_jit_domain_info);
3915 mono_install_free_domain_hook (mini_free_jit_domain_info);
3917 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3918 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3919 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3921 if (mini_profiler_enabled ()) {
3922 mono_profiler_load (mini_profiler_get_options ());
3923 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3926 if (debug_options.collect_pagefault_stats)
3927 mono_aot_set_make_unreadable (TRUE);
3929 if (runtime_version)
3930 domain = mono_init_version (filename, runtime_version);
3932 domain = mono_init_from_assembly (filename, filename);
3934 if (mono_aot_only) {
3935 /* This helps catch code allocation requests */
3936 mono_code_manager_set_read_only (domain->code_mp);
3937 mono_marshal_use_aot_wrappers (TRUE);
3940 if (mono_llvm_only) {
3941 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3942 mono_set_always_build_imt_trampolines (TRUE);
3943 } else if (mono_aot_only) {
3944 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3946 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3949 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3950 mono_arch_finish_init ();
3954 /* This must come after mono_init () in the aot-only case */
3955 mono_exceptions_init ();
3957 /* This should come after mono_init () too */
3961 mono_create_helper_signatures ();
3964 register_jit_stats ();
3966 #define JIT_CALLS_WORK
3967 #ifdef JIT_CALLS_WORK
3968 /* Needs to be called here since register_jit_icall depends on it */
3969 mono_marshal_init ();
3971 mono_arch_register_lowlevel_calls ();
3975 mono_generic_sharing_init ();
3978 #ifdef MONO_ARCH_SIMD_INTRINSICS
3979 mono_simd_intrinsics_init ();
3982 mono_tasklets_init ();
3984 register_trampolines (domain);
3986 if (mono_compile_aot)
3988 * Avoid running managed code when AOT compiling, since the platform
3989 * might only support aot-only execution.
3991 mono_runtime_set_no_exec (TRUE);
3993 mono_mem_account_register_counters ();
3995 #define JIT_RUNTIME_WORKS
3996 #ifdef JIT_RUNTIME_WORKS
3997 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
3998 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
3999 mono_error_assert_ok (&error);
4000 mono_thread_attach (domain);
4003 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4004 mono_runtime_setup_stat_profiler ();
4006 mono_profiler_runtime_initialized ();
4008 MONO_VES_INIT_END ();
4014 register_icalls (void)
4016 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4017 ves_icall_get_frame_info);
4018 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4019 ves_icall_get_trace);
4020 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4021 mono_runtime_install_handlers);
4022 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4023 mono_runtime_cleanup_handlers);
4025 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4026 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4027 mono_debugger_agent_unhandled_exception);
4031 * It's important that we pass `TRUE` as the last argument here, as
4032 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4033 * *did* emit a wrapper, we'd be looking at infinite recursion since
4034 * the wrapper would call the icall which would call the wrapper and
4037 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4038 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4040 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4041 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4042 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4043 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4044 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4045 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4047 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4048 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4049 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4050 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4051 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4052 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4053 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4054 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4055 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4057 // FIXME: This is broken
4058 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4061 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4062 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4063 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4064 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4065 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4066 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4068 #if defined(__native_client__) || defined(__native_client_codegen__)
4069 register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
4072 if (mono_threads_is_coop_enabled ())
4073 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4075 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4076 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4077 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4078 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4079 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4080 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4082 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4083 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4084 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4087 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4088 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4089 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4090 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4093 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4094 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4095 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4096 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4097 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4100 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4101 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4104 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4105 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4106 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4109 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4110 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4113 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4114 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4115 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4116 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4117 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4118 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4119 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4122 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4123 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4124 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4127 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4128 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);
4130 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4131 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4133 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4134 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4136 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4137 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);
4139 #ifdef MONO_ARCH_EMULATE_FREM
4140 #if !defined(__native_client__)
4141 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4142 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4144 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
4148 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4149 if (mono_arch_is_soft_float ()) {
4150 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4151 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4152 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4153 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4154 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4155 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4156 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4157 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4158 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4159 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4160 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4161 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4163 #if SIZEOF_VOID_P == 4
4164 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4167 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4168 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4169 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4170 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4171 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4172 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4173 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4174 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4175 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4176 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4178 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4179 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4180 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4181 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4182 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4184 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4185 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4186 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4187 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4190 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4192 #ifdef COMPRESSED_INTERFACE_BITMAP
4193 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4196 #if SIZEOF_REGISTER == 4
4197 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4199 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4202 /* other jit icalls */
4203 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4204 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4205 "ptr ptr ptr", FALSE);
4206 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4207 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4208 "ptr ptr ptr ptr", FALSE);
4209 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4210 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4211 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4212 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4213 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4214 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4215 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4216 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4217 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4218 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4219 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4220 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4221 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4222 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4223 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4224 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4225 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4226 register_icall (mono_break, "mono_break", NULL, TRUE);
4227 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4228 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4229 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4230 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4231 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4232 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4233 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4234 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4235 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4236 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4237 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4239 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int");
4241 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4242 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4243 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4244 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4245 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4247 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4249 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4250 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4251 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4252 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4254 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4255 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4256 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4257 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4258 /* This needs a wrapper so it can have a preserveall cconv */
4259 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4260 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4261 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4262 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4263 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4264 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4265 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4267 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4268 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4269 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4270 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4273 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4275 /* Register tls icalls */
4276 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4277 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4278 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4279 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4280 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4281 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4282 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4283 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4284 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4285 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4288 MonoJitStats mono_jit_stats = {0};
4291 print_jit_stats (void)
4293 if (mono_jit_stats.enabled) {
4294 g_print ("Mono Jit statistics\n");
4295 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4296 mono_jit_stats.max_ratio_method);
4297 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4298 mono_jit_stats.biggest_method);
4300 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4301 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4302 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4303 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4304 g_print ("Methods: %ld\n", mono_stats.method_count);
4305 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4306 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4307 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4309 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4310 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4311 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4313 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4314 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4315 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4316 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4318 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4319 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4320 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4321 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4322 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4323 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4324 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4325 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4327 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4328 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4329 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4331 g_free (mono_jit_stats.max_ratio_method);
4332 mono_jit_stats.max_ratio_method = NULL;
4333 g_free (mono_jit_stats.biggest_method);
4334 mono_jit_stats.biggest_method = NULL;
4339 mini_cleanup (MonoDomain *domain)
4341 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4342 mono_runtime_shutdown_stat_profiler ();
4345 cominterop_release_all_rcws ();
4348 #ifndef MONO_CROSS_COMPILE
4350 * mono_domain_finalize () needs to be called early since it needs the
4351 * execution engine still fully working (it may invoke managed finalizers).
4353 mono_domain_finalize (domain, 2000);
4356 /* This accesses metadata so needs to be called before runtime shutdown */
4359 #ifndef MONO_CROSS_COMPILE
4360 mono_runtime_cleanup (domain);
4363 mono_threadpool_cleanup ();
4365 mono_profiler_shutdown ();
4367 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4369 mono_icall_cleanup ();
4371 mono_runtime_cleanup_handlers ();
4373 #ifndef MONO_CROSS_COMPILE
4374 mono_domain_free (domain, TRUE);
4379 mono_llvm_cleanup ();
4382 mono_aot_cleanup ();
4384 mono_trampolines_cleanup ();
4386 mono_unwind_cleanup ();
4388 mono_code_manager_destroy (global_codeman);
4389 g_free (vtable_trampolines);
4391 mini_jit_cleanup ();
4393 mono_tramp_info_cleanup ();
4395 mono_arch_cleanup ();
4397 mono_generic_sharing_cleanup ();
4401 mono_trace_cleanup ();
4403 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4405 if (mono_inject_async_exc_method)
4406 mono_method_desc_free (mono_inject_async_exc_method);
4408 mono_tls_free_keys ();
4410 mono_os_mutex_destroy (&jit_mutex);
4412 mono_code_manager_cleanup ();
4415 mono_w32handle_cleanup ();
4420 mono_set_defaults (int verbose_level, guint32 opts)
4422 mini_verbose = verbose_level;
4423 mono_set_optimizations (opts);
4427 mono_disable_optimizations (guint32 opts)
4429 default_opt &= ~opts;
4433 mono_set_optimizations (guint32 opts)
4436 default_opt_set = TRUE;
4437 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4438 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4441 mono_set_generic_sharing_vt_supported (TRUE);
4446 mono_set_verbose_level (guint32 level)
4448 mini_verbose = level;
4452 * mono_get_runtime_build_info:
4453 * The returned string is owned by the caller. The returned string
4454 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4455 * \returns the runtime version + build date in string format.
4458 mono_get_runtime_build_info (void)
4460 if (mono_build_date)
4461 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4463 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4467 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4469 GHashTable *assemblies = (GHashTable*)user_data;
4470 MonoImage *image = mono_assembly_get_image (ass);
4471 MonoMethod *method, *invoke;
4474 if (g_hash_table_lookup (assemblies, ass))
4477 g_hash_table_insert (assemblies, ass, ass);
4479 if (mini_verbose > 0)
4480 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4482 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4485 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4487 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4490 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4492 if (method->is_generic || mono_class_is_gtd (method->klass))
4496 if (mini_verbose > 1) {
4497 char * desc = mono_method_full_name (method, TRUE);
4498 g_print ("Compiling %d %s\n", count, desc);
4501 mono_compile_method_checked (method, &error);
4502 if (!is_ok (&error)) {
4503 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4506 if (strcmp (method->name, "Finalize") == 0) {
4507 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4508 mono_compile_method_checked (invoke, &error);
4509 mono_error_assert_ok (&error);
4511 #ifndef DISABLE_REMOTING
4512 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4513 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4514 mono_compile_method_checked (invoke, &error);
4515 mono_error_assert_ok (&error);
4520 /* Load and precompile referenced assemblies as well */
4521 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4522 mono_assembly_load_reference (image, i);
4523 if (image->references [i])
4524 mono_precompile_assembly (image->references [i], assemblies);
4528 void mono_precompile_assemblies ()
4530 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4532 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4534 g_hash_table_destroy (assemblies);
4539 * Have to export this for AOT.
4542 mono_personality (void)
4545 g_assert_not_reached ();
4548 // Custom handlers currently only implemented by Windows.
4551 mono_runtime_install_custom_handlers (const char *handlers)
4557 mono_runtime_install_custom_handlers_usage (void)
4560 "Custom Handlers:\n"
4561 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4562 " separated list of available handlers to install.\n"
4564 "No handlers supported on current platform.\n");
4566 #endif /* HOST_WIN32 */