3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include "mono/metadata/profiler.h"
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/utils/mono-math.h>
55 #include <mono/utils/mono-compiler.h>
56 #include <mono/utils/mono-counters.h>
57 #include <mono/utils/mono-error-internals.h>
58 #include <mono/utils/mono-logger-internals.h>
59 #include <mono/utils/mono-mmap.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-tls.h>
62 #include <mono/utils/mono-hwcap.h>
63 #include <mono/utils/dtrace.h>
64 #include <mono/utils/mono-signal-handler.h>
65 #include <mono/utils/mono-threads.h>
66 #include <mono/utils/mono-threads-coop.h>
67 #include <mono/utils/checked-build.h>
68 #include <mono/utils/mono-proclib.h>
69 #include <mono/metadata/w32handle.h>
70 #include <mono/metadata/threadpool.h>
73 #include "seq-points.h"
80 #include "jit-icalls.h"
83 #include "mini-llvm.h"
84 #include "debugger-agent.h"
87 #ifdef MONO_ARCH_LLVM_SUPPORTED
89 #include "mini-llvm-cpp.h"
94 #ifdef ENABLE_INTERPRETER
95 #include "interp/interp.h"
98 static guint32 default_opt = 0;
99 static gboolean default_opt_set = FALSE;
101 gboolean mono_compile_aot = FALSE;
102 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
103 gboolean mono_aot_only = FALSE;
104 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
105 gboolean mono_llvm_only = FALSE;
106 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NONE;
108 const char *mono_build_date;
109 gboolean mono_do_signal_chaining;
110 gboolean mono_do_crash_chaining;
111 int mini_verbose = 0;
114 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
115 * it can load AOT code compiled by LLVM.
117 gboolean mono_use_llvm = FALSE;
119 gboolean mono_use_interpreter = FALSE;
121 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
122 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
123 static mono_mutex_t jit_mutex;
125 static MonoCodeManager *global_codeman;
127 MonoDebugOptions debug_options;
129 #ifdef VALGRIND_JIT_REGISTER_MAP
130 int valgrind_register;
132 GList* mono_aot_paths;
134 static gboolean mini_enable_profiler = FALSE;
135 static char* mini_profiler_options = NULL;
137 static GSList *tramp_infos;
139 static void register_icalls (void);
141 static gboolean mini_profiler_enabled (void) { return mini_enable_profiler; }
142 static const char* mini_profiler_get_options (void) { return mini_profiler_options; }
145 mono_running_on_valgrind (void)
148 if (RUNNING_ON_VALGRIND){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register = TRUE;
164 find_tramp (gpointer key, gpointer value, gpointer user_data)
166 FindTrampUserData *ud = (FindTrampUserData*)user_data;
169 ud->method = (MonoMethod*)key;
173 G_GNUC_UNUSED static char*
174 get_method_from_ip (void *ip)
180 MonoDomain *domain = mono_domain_get ();
181 MonoDebugSourceLocation *location;
182 FindTrampUserData user_data;
185 domain = mono_get_root_domain ();
187 ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
190 user_data.method = NULL;
191 mono_domain_lock (domain);
192 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
193 mono_domain_unlock (domain);
194 if (user_data.method) {
195 char *mname = mono_method_full_name (user_data.method, TRUE);
196 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
202 } else if (ji->is_trampoline) {
203 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
207 method = jinfo_get_method (ji);
208 method_name = mono_method_full_name (method, TRUE);
209 /* FIXME: unused ? */
210 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
212 res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
214 mono_debug_free_source_location (location);
215 g_free (method_name);
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
235 return get_method_from_ip (ip);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
250 mono_print_method_from_ip (void *ip)
254 MonoDebugSourceLocation *source;
255 MonoDomain *domain = mono_domain_get ();
256 MonoDomain *target_domain = mono_domain_get ();
257 FindTrampUserData user_data;
258 MonoGenericSharingContext*gsctx;
259 const char *shared_type;
262 domain = mono_get_root_domain ();
263 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
264 if (ji && ji->is_trampoline) {
265 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
273 user_data.method = NULL;
274 mono_domain_lock (domain);
275 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
276 mono_domain_unlock (domain);
278 if (user_data.method) {
279 char *mname = mono_method_full_name (user_data.method, TRUE);
280 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
285 g_print ("No method at %p\n", ip);
289 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
290 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
292 gsctx = mono_jit_info_get_generic_sharing_context (ji);
295 if (gsctx->is_gsharedvt)
296 shared_type = "gsharedvt ";
298 shared_type = "gshared ";
301 g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
304 g_print ("%s:%d\n", source->source_file, source->row);
307 mono_debug_free_source_location (source);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
321 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller->domain_neutral && !callee->domain_neutral)
331 cmethod = jinfo_get_method (caller);
332 if ((cmethod->klass == mono_defaults.appdomain_class) &&
333 (strstr (cmethod->name, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman) {
354 /* This can happen during startup */
355 global_codeman = mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman, size);
360 ptr = mono_code_manager_reserve (global_codeman, size);
366 /* The callback shouldn't take any locks */
368 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
371 mono_code_manager_foreach (global_codeman, func, user_data);
375 #if defined(__native_client_codegen__) && defined(__native_client__)
379 #ifdef __native_client_gc__
380 __nacl_suspend_thread_if_needed();
383 #endif /* __native_client__ */
386 * mono_create_unwind_op:
388 * Create an unwind op with the given parameters.
391 mono_create_unwind_op (int when, int tag, int reg, int val)
393 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
404 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
406 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
409 res->has_context = context != NULL;
411 memcpy (&res->context, context, sizeof (MonoGenericContext));
417 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
419 return mono_jump_info_token_new2 (mp, image, token, NULL);
423 * mono_tramp_info_create:
425 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
426 * of JI, and UNWIND_OPS.
429 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
431 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
433 info->name = g_strdup ((char*)name);
435 info->code_size = code_size;
437 info->unwind_ops = unwind_ops;
443 mono_tramp_info_free (MonoTrampInfo *info)
448 mono_free_unwind_info (info->unwind_ops);
449 if (info->owns_uw_info)
450 g_free (info->uw_info);
455 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
459 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
460 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
461 ji->d.tramp_info = info;
462 ji->is_trampoline = TRUE;
464 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
466 mono_jit_info_table_add (domain, ji);
470 * mono_tramp_info_register:
472 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
477 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
485 domain = mono_get_root_domain ();
487 copy = g_new0 (MonoTrampInfo, 1);
488 copy->code = info->code;
489 copy->code_size = info->code_size;
490 copy->name = g_strdup (info->name);
492 if (info->unwind_ops) {
493 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
494 copy->owns_uw_info = TRUE;
496 /* Trampolines from aot have the unwind ops already encoded */
497 copy->uw_info = info->uw_info;
498 copy->uw_info_len = info->uw_info_len;
502 tramp_infos = g_slist_prepend (tramp_infos, copy);
505 mono_save_trampoline_xdebug_info (info);
506 mono_lldb_save_trampoline_info (info);
508 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
510 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
513 /* Only register trampolines that have unwind infos */
514 if (mono_get_root_domain () && copy->uw_info)
515 register_trampoline_jit_info (domain, copy);
517 if (mono_jit_map_is_enabled ())
518 mono_emit_jit_tramp (info->code, info->code_size, info->name);
520 mono_tramp_info_free (info);
524 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
526 mono_tramp_info_register_internal (info, domain, FALSE);
530 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
532 mono_tramp_info_register_internal (info, domain, TRUE);
536 mono_tramp_info_cleanup (void)
540 for (l = tramp_infos; l; l = l->next) {
541 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
543 mono_tramp_info_free (info);
545 g_slist_free (tramp_infos);
548 /* Register trampolines created before the root domain was created in the jit info tables */
550 register_trampolines (MonoDomain *domain)
554 for (l = tramp_infos; l; l = l->next) {
555 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
557 register_trampoline_jit_info (domain, info);
561 G_GNUC_UNUSED static void
567 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
568 * Set a breakpoint in break_count () to break the last time <x> is done.
570 G_GNUC_UNUSED gboolean
571 mono_debug_count (void)
573 static int count = 0;
574 static gboolean inited;
580 value = g_getenv ("COUNT");
587 int int_val = atoi (value);
590 if (count == int_val)
600 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
605 gconstpointer trampoline;
606 MonoDomain *domain = mono_get_root_domain ();
607 gboolean check_exc = TRUE;
609 if (callinfo->wrapper)
610 return callinfo->wrapper;
612 if (callinfo->trampoline)
613 return callinfo->trampoline;
615 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
616 /* This icall is used to check for exceptions, so don't check in the wrapper */
619 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
620 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
624 trampoline = mono_compile_method_checked (wrapper, &error);
625 mono_error_assert_ok (&error);
628 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
629 mono_error_assert_ok (&error);
630 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
634 if (!callinfo->trampoline) {
635 mono_register_jit_icall_wrapper (callinfo, trampoline);
636 callinfo->trampoline = trampoline;
638 mono_loader_unlock ();
640 return callinfo->trampoline;
644 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
646 return mono_icall_get_wrapper_full (callinfo, FALSE);
649 static MonoJitDynamicMethodInfo*
650 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
652 MonoJitDynamicMethodInfo *res;
654 if (domain_jit_info (domain)->dynamic_code_hash)
655 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
662 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
665 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
667 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
669 g_assert (!sig->hasthis);
670 g_assert (sig->param_count < 3);
672 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
673 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
678 * For JIT icalls implemented in C.
679 * NAME should be the same as the name of the C function whose address is FUNC.
680 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
681 * can't throw exceptions.
684 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
686 MonoMethodSignature *sig;
689 sig = mono_create_icall_signature (sigstr);
693 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, FALSE, avoid_wrapper ? name : NULL);
697 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
699 MonoMethodSignature *sig;
702 sig = mono_create_icall_signature (sigstr);
706 mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
710 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
712 MonoMethodSignature *sig;
715 sig = mono_create_icall_signature (sigstr);
719 mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
723 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
725 MonoMethodSignature *sig;
728 sig = mono_create_icall_signature (sigstr);
732 mono_register_jit_icall (func, name, sig, save);
738 MonoJitTlsData *jit_tls;
740 if ((jit_tls = mono_tls_get_jit_tls ()))
743 * We do not assert here because this function can be called from
744 * mini-gc.c on a thread that has not executed any managed code, yet
745 * (the thread object allocation can trigger a collection).
751 mono_get_lmf_addr (void)
753 return (MonoLMF **)mono_tls_get_lmf_addr ();
757 mono_set_lmf (MonoLMF *lmf)
759 (*mono_get_lmf_addr ()) = lmf;
763 mono_get_jit_tls (void)
765 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
769 mono_set_jit_tls (MonoJitTlsData *jit_tls)
771 MonoThreadInfo *info;
773 mono_tls_set_jit_tls (jit_tls);
775 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
776 info = mono_thread_info_current ();
778 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
782 mono_set_lmf_addr (gpointer lmf_addr)
784 MonoThreadInfo *info;
786 mono_tls_set_lmf_addr (lmf_addr);
788 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
789 info = mono_thread_info_current ();
791 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
797 * Push an MonoLMFExt frame on the LMF stack.
800 mono_push_lmf (MonoLMFExt *ext)
802 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
805 lmf_addr = mono_get_lmf_addr ();
807 mono_arch_init_lmf_ext (ext, *lmf_addr);
809 mono_set_lmf ((MonoLMF*)ext);
818 * Pop the last frame from the LMF stack.
821 mono_pop_lmf (MonoLMF *lmf)
823 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
827 * mono_jit_thread_attach:
829 * Called by Xamarin.Mac and other products. Attach thread to runtime if
830 * needed and switch to @domain.
832 * @return the original domain which needs to be restored, or NULL.
835 mono_jit_thread_attach (MonoDomain *domain)
840 g_assert (!mono_threads_is_coop_enabled ());
843 /* Happens when called from AOTed code which is only used in the root domain. */
844 domain = mono_get_root_domain ();
849 attached = mono_tls_get_jit_tls () != NULL;
852 mono_thread_attach (domain);
855 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
858 orig = mono_domain_get ();
860 mono_domain_set (domain, TRUE);
862 return orig != domain ? orig : NULL;
866 * mono_jit_set_domain:
868 * Set domain to @domain if @domain is not null
871 mono_jit_set_domain (MonoDomain *domain)
873 g_assert (!mono_threads_is_coop_enabled ());
876 mono_domain_set (domain, TRUE);
881 * \param obj exception object
882 * Abort the thread, print exception information and stack trace
885 mono_thread_abort (MonoObject *obj)
887 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
889 /* handle_remove should be eventually called for this thread, too
892 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
893 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
896 mono_invoke_unhandled_exception_hook (obj);
901 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
903 MonoJitTlsData *jit_tls;
906 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
910 jit_tls = g_new0 (MonoJitTlsData, 1);
912 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
913 jit_tls->end_of_stack = stack_start;
915 mono_set_jit_tls (jit_tls);
917 lmf = g_new0 (MonoLMF, 1);
918 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
920 jit_tls->first_lmf = lmf;
922 mono_set_lmf_addr (&jit_tls->lmf);
926 #ifdef MONO_ARCH_HAVE_TLS_INIT
927 mono_arch_tls_init ();
930 mono_setup_altstack (jit_tls);
936 free_jit_tls_data (MonoJitTlsData *jit_tls)
938 mono_arch_free_jit_tls_data (jit_tls);
939 mono_free_altstack (jit_tls);
941 g_free (jit_tls->first_lmf);
946 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
948 MonoThreadInfo *thread;
949 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
950 thread = mono_thread_info_current_unchecked ();
952 thread->jit_data = jit_tls;
954 mono_arch_cpu_init ();
957 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
960 mono_thread_abort_dummy (MonoObject *obj)
962 if (mono_thread_attach_aborted_cb)
963 mono_thread_attach_aborted_cb (obj);
965 mono_thread_abort (obj);
969 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
971 MonoThreadInfo *thread;
972 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
973 thread = mono_thread_info_current_unchecked ();
975 thread->jit_data = jit_tls;
977 mono_arch_cpu_init ();
981 mini_thread_cleanup (MonoNativeThreadId tid)
983 MonoJitTlsData *jit_tls = NULL;
984 MonoThreadInfo *info;
986 info = mono_thread_info_current_unchecked ();
988 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
989 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
990 * not a trivial thing.
992 * The current offender is mono_thread_manage which cleanup threads from the outside.
994 if (info && mono_thread_info_get_tid (info) == tid) {
995 jit_tls = (MonoJitTlsData *)info->jit_data;
996 info->jit_data = NULL;
998 mono_set_jit_tls (NULL);
1000 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1001 if (mono_get_lmf ()) {
1002 mono_set_lmf (NULL);
1003 mono_set_lmf_addr (NULL);
1006 info = mono_thread_info_lookup (tid);
1008 jit_tls = (MonoJitTlsData *)info->jit_data;
1009 info->jit_data = NULL;
1011 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1015 free_jit_tls_data (jit_tls);
1019 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1021 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1025 ji->data.target = target;
1031 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1033 static const char* const patch_info_str[] = {
1034 #define PATCH_INFO(a,b) "" #a,
1035 #include "patch-info.h"
1040 mono_ji_type_to_string (MonoJumpInfoType type)
1042 return patch_info_str [type];
1046 mono_print_ji (const MonoJumpInfo *ji)
1049 case MONO_PATCH_INFO_RGCTX_FETCH: {
1050 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1052 printf ("[RGCTX_FETCH ");
1053 mono_print_ji (entry->data);
1054 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1057 case MONO_PATCH_INFO_METHODCONST: {
1058 char *s = mono_method_full_name (ji->data.method, TRUE);
1059 printf ("[METHODCONST - %s]", s);
1063 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1064 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1068 printf ("[%s]", patch_info_str [ji->type]);
1076 mono_ji_type_to_string (MonoJumpInfoType type)
1082 mono_print_ji (const MonoJumpInfo *ji)
1089 * mono_patch_info_dup_mp:
1091 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1094 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1096 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1097 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1099 switch (patch_info->type) {
1100 case MONO_PATCH_INFO_RVA:
1101 case MONO_PATCH_INFO_LDSTR:
1102 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1103 case MONO_PATCH_INFO_LDTOKEN:
1104 case MONO_PATCH_INFO_DECLSEC:
1105 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1106 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1108 case MONO_PATCH_INFO_SWITCH:
1109 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1110 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1111 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1112 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1114 case MONO_PATCH_INFO_RGCTX_FETCH:
1115 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1116 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1117 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1118 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1120 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1121 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1122 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1124 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1125 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1126 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1128 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1129 MonoGSharedVtMethodInfo *info;
1130 MonoGSharedVtMethodInfo *oinfo;
1133 oinfo = patch_info->data.gsharedvt_method;
1134 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1135 res->data.gsharedvt_method = info;
1136 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1137 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1138 for (i = 0; i < oinfo->num_entries; ++i) {
1139 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1140 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1142 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1144 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1145 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1148 case MONO_PATCH_INFO_VIRT_METHOD: {
1149 MonoJumpInfoVirtMethod *info;
1150 MonoJumpInfoVirtMethod *oinfo;
1152 oinfo = patch_info->data.virt_method;
1153 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1154 res->data.virt_method = info;
1155 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1166 mono_patch_info_hash (gconstpointer data)
1168 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1171 case MONO_PATCH_INFO_RVA:
1172 case MONO_PATCH_INFO_LDSTR:
1173 case MONO_PATCH_INFO_LDTOKEN:
1174 case MONO_PATCH_INFO_DECLSEC:
1175 return (ji->type << 8) | ji->data.token->token;
1176 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1177 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1178 case MONO_PATCH_INFO_INTERNAL_METHOD:
1179 return (ji->type << 8) | g_str_hash (ji->data.name);
1180 case MONO_PATCH_INFO_VTABLE:
1181 case MONO_PATCH_INFO_CLASS:
1182 case MONO_PATCH_INFO_IID:
1183 case MONO_PATCH_INFO_ADJUSTED_IID:
1184 case MONO_PATCH_INFO_METHODCONST:
1185 case MONO_PATCH_INFO_METHOD:
1186 case MONO_PATCH_INFO_METHOD_JUMP:
1187 case MONO_PATCH_INFO_IMAGE:
1188 case MONO_PATCH_INFO_ICALL_ADDR:
1189 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1190 case MONO_PATCH_INFO_FIELD:
1191 case MONO_PATCH_INFO_SFLDA:
1192 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1193 case MONO_PATCH_INFO_METHOD_RGCTX:
1194 case MONO_PATCH_INFO_SIGNATURE:
1195 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1196 case MONO_PATCH_INFO_AOT_JIT_INFO:
1197 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1198 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1199 return (ji->type << 8) | (gssize)ji->data.target;
1200 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1201 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1202 case MONO_PATCH_INFO_RGCTX_FETCH:
1203 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1204 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1206 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1208 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1209 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1210 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1211 case MONO_PATCH_INFO_GC_NURSERY_START:
1212 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1213 case MONO_PATCH_INFO_GOT_OFFSET:
1214 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1215 case MONO_PATCH_INFO_AOT_MODULE:
1216 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1217 return (ji->type << 8);
1218 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1219 return (ji->type << 8) | (ji->data.index);
1220 case MONO_PATCH_INFO_SWITCH:
1221 return (ji->type << 8) | ji->data.table->table_size;
1222 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1223 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1224 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1225 /* Hash on the selector name */
1226 return g_str_hash (ji->data.target);
1227 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1228 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1229 case MONO_PATCH_INFO_LDSTR_LIT:
1230 return g_str_hash (ji->data.target);
1231 case MONO_PATCH_INFO_VIRT_METHOD: {
1232 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1234 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1236 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1237 return (ji->type << 8) | g_str_hash (ji->data.target);
1238 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1239 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1241 printf ("info type: %d\n", ji->type);
1242 mono_print_ji (ji); printf ("\n");
1243 g_assert_not_reached ();
1249 * mono_patch_info_equal:
1251 * This might fail to recognize equivalent patches, i.e. floats, so its only
1252 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1256 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1258 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1259 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1261 if (ji1->type != ji2->type)
1264 switch (ji1->type) {
1265 case MONO_PATCH_INFO_RVA:
1266 case MONO_PATCH_INFO_LDSTR:
1267 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1268 case MONO_PATCH_INFO_LDTOKEN:
1269 case MONO_PATCH_INFO_DECLSEC:
1270 if ((ji1->data.token->image != ji2->data.token->image) ||
1271 (ji1->data.token->token != ji2->data.token->token) ||
1272 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1273 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1274 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1277 case MONO_PATCH_INFO_INTERNAL_METHOD:
1278 return g_str_equal (ji1->data.name, ji2->data.name);
1279 case MONO_PATCH_INFO_RGCTX_FETCH:
1280 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1281 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1282 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1284 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);
1286 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1287 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1288 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1290 return c1->sig == c2->sig && c1->method == c2->method;
1292 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1293 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1294 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1295 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;
1296 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1297 return ji1->data.index == ji2->data.index;
1298 case MONO_PATCH_INFO_VIRT_METHOD:
1299 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1300 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1301 if (ji1->data.target == ji2->data.target)
1303 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1304 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1305 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1307 if (ji1->data.target != ji2->data.target)
1316 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1318 unsigned char *ip = patch_info->ip.i + code;
1319 gconstpointer target = NULL;
1323 switch (patch_info->type) {
1324 case MONO_PATCH_INFO_BB:
1326 * FIXME: This could be hit for methods without a prolog. Should use -1
1327 * but too much code depends on a 0 initial value.
1329 //g_assert (patch_info->data.bb->native_offset);
1330 target = patch_info->data.bb->native_offset + code;
1332 case MONO_PATCH_INFO_ABS:
1333 target = patch_info->data.target;
1335 case MONO_PATCH_INFO_LABEL:
1336 target = patch_info->data.inst->inst_c0 + code;
1338 case MONO_PATCH_INFO_IP:
1341 case MONO_PATCH_INFO_METHOD_REL:
1342 target = code + patch_info->data.offset;
1344 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1345 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1347 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1348 g_assert_not_reached ();
1350 target = mono_icall_get_wrapper (mi);
1353 case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
1354 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1356 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1357 g_assert_not_reached ();
1362 case MONO_PATCH_INFO_METHOD_JUMP:
1363 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1364 if (!mono_error_ok (error))
1367 case MONO_PATCH_INFO_METHOD:
1368 if (patch_info->data.method == method) {
1371 /* get the trampoline to the method from the domain */
1372 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1373 if (!mono_error_ok (error))
1377 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1380 mono_domain_lock (domain);
1381 if (!domain_jit_info (domain)->method_code_hash)
1382 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1383 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1385 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1386 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1388 mono_domain_unlock (domain);
1392 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1393 #if defined(__native_client_codegen__)
1394 target = (gpointer)&__nacl_thread_suspension_needed;
1396 g_assert (mono_threads_is_coop_enabled ());
1397 target = (gpointer)&mono_polling_required;
1400 case MONO_PATCH_INFO_SWITCH: {
1401 gpointer *jump_table;
1403 #if defined(__native_client__) && defined(__native_client_codegen__)
1404 /* This memory will leak, but we don't care if we're */
1405 /* not deleting JIT'd methods anyway */
1406 jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
1408 if (method && method->dynamic) {
1409 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1411 if (mono_aot_only) {
1412 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1414 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1419 for (i = 0; i < patch_info->data.table->table_size; i++) {
1420 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1423 target = jump_table;
1426 case MONO_PATCH_INFO_METHODCONST:
1427 case MONO_PATCH_INFO_CLASS:
1428 case MONO_PATCH_INFO_IMAGE:
1429 case MONO_PATCH_INFO_FIELD:
1430 case MONO_PATCH_INFO_SIGNATURE:
1431 case MONO_PATCH_INFO_AOT_MODULE:
1432 target = patch_info->data.target;
1434 case MONO_PATCH_INFO_IID:
1435 mono_class_init (patch_info->data.klass);
1436 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1438 case MONO_PATCH_INFO_ADJUSTED_IID:
1439 mono_class_init (patch_info->data.klass);
1440 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1442 case MONO_PATCH_INFO_VTABLE:
1443 target = mono_class_vtable (domain, patch_info->data.klass);
1446 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1447 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1449 if (del_tramp->is_virtual)
1450 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1452 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1455 case MONO_PATCH_INFO_SFLDA: {
1456 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1458 if (mono_class_field_is_special_static (patch_info->data.field)) {
1459 gpointer addr = NULL;
1461 mono_domain_lock (domain);
1462 if (domain->special_static_fields)
1463 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1464 mono_domain_unlock (domain);
1470 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1471 /* Done by the generated code */
1475 if (!mono_runtime_class_init_full (vtable, error)) {
1480 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1483 case MONO_PATCH_INFO_RVA: {
1484 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1487 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1488 target = mono_image_rva_map (patch_info->data.token->image, rva);
1491 case MONO_PATCH_INFO_R4:
1492 case MONO_PATCH_INFO_R8:
1493 target = patch_info->data.target;
1495 case MONO_PATCH_INFO_EXC_NAME:
1496 target = patch_info->data.name;
1498 case MONO_PATCH_INFO_LDSTR:
1500 mono_ldstr_checked (domain, patch_info->data.token->image,
1501 mono_metadata_token_index (patch_info->data.token->token), error);
1503 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1505 MonoClass *handle_class;
1507 handle = mono_ldtoken_checked (patch_info->data.token->image,
1508 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1509 if (!mono_error_ok (error))
1511 mono_class_init (handle_class);
1512 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1514 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1515 if (!mono_error_ok (error))
1519 case MONO_PATCH_INFO_LDTOKEN: {
1521 MonoClass *handle_class;
1523 handle = mono_ldtoken_checked (patch_info->data.token->image,
1524 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1525 if (!mono_error_ok (error))
1526 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1527 mono_class_init (handle_class);
1532 case MONO_PATCH_INFO_DECLSEC:
1533 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1535 case MONO_PATCH_INFO_ICALL_ADDR:
1536 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1537 /* run_cctors == 0 -> AOT */
1538 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1539 const char *exc_class;
1540 const char *exc_arg;
1543 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1545 if (mono_aot_only) {
1546 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1549 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));
1555 target = mono_lookup_internal_call (patch_info->data.method);
1557 if (!target && run_cctors)
1558 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1561 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1562 target = mono_thread_interruption_request_flag ();
1564 case MONO_PATCH_INFO_METHOD_RGCTX: {
1565 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1568 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1571 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1572 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1574 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1577 case MONO_PATCH_INFO_BB_OVF:
1578 case MONO_PATCH_INFO_EXC_OVF:
1579 case MONO_PATCH_INFO_GOT_OFFSET:
1580 case MONO_PATCH_INFO_NONE:
1582 case MONO_PATCH_INFO_RGCTX_FETCH: {
1583 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1585 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1588 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1589 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1591 /* AOT, not needed */
1594 target = mono_arch_get_seq_point_info (domain, code);
1597 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1598 int card_table_shift_bits;
1599 gpointer card_table_mask;
1601 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1604 case MONO_PATCH_INFO_GC_NURSERY_START: {
1608 target = mono_gc_get_nursery (&shift_bits, &size);
1611 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1615 mono_gc_get_nursery (&shift_bits, &size);
1617 target = (gpointer)(mgreg_t)shift_bits;
1620 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1621 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1624 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1628 case MONO_PATCH_INFO_LDSTR_LIT: {
1632 len = strlen ((const char *)patch_info->data.target);
1633 s = (char *)mono_domain_alloc0 (domain, len + 1);
1634 memcpy (s, patch_info->data.target, len);
1639 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1640 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1642 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1643 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1645 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1646 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1648 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1649 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1655 g_assert_not_reached ();
1658 return (gpointer)target;
1662 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1664 MonoGenericInst *inst;
1667 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1669 if (context && context->class_inst) {
1670 inst = context->class_inst;
1671 for (i = 0; i < inst->type_argc; ++i) {
1672 MonoType *type = inst->type_argv [i];
1674 if (mini_is_gsharedvt_gparam (type))
1675 gsctx->is_gsharedvt = TRUE;
1678 if (context && context->method_inst) {
1679 inst = context->method_inst;
1681 for (i = 0; i < inst->type_argc; ++i) {
1682 MonoType *type = inst->type_argv [i];
1684 if (mini_is_gsharedvt_gparam (type))
1685 gsctx->is_gsharedvt = TRUE;
1691 * LOCKING: Acquires the jit code hash lock.
1694 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1697 static gboolean inited = FALSE;
1698 static int lookups = 0;
1699 static int failed_lookups = 0;
1701 mono_domain_jit_code_hash_lock (domain);
1702 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1703 if (!ji && shared) {
1704 /* Try generic sharing */
1705 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1706 if (ji && !ji->has_generic_jit_info)
1709 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1710 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1718 mono_domain_jit_code_hash_unlock (domain);
1724 lookup_method (MonoDomain *domain, MonoMethod *method)
1729 ji = mini_lookup_method (domain, method, NULL);
1732 if (!mono_method_is_generic_sharable (method, FALSE))
1734 shared = mini_get_shared_method (method);
1735 ji = mini_lookup_method (domain, method, shared);
1742 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1744 return lookup_method (domain, method);
1748 static FILE* perf_map_file;
1751 mono_enable_jit_map (void)
1753 if (!perf_map_file) {
1755 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1757 perf_map_file = fopen (name, "w");
1762 mono_emit_jit_tramp (void *start, int size, const char *desc)
1765 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1769 mono_emit_jit_map (MonoJitInfo *jinfo)
1771 if (perf_map_file) {
1772 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1773 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1779 mono_jit_map_is_enabled (void)
1781 return perf_map_file != NULL;
1787 no_gsharedvt_in_wrapper (void)
1789 g_assert_not_reached ();
1795 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.
1796 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1797 Dependency management in this case is too complex to justify implementing it.
1799 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1802 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1803 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1804 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1805 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1810 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1811 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1812 int threads_waiting; /* Number of threads waiting on this job */
1813 gboolean has_cond; /* True if @cond was initialized */
1814 gboolean done; /* True if the method finished JIT'ing */
1815 MonoCoopCond cond; /* Cond sleeping threads wait one */
1816 } JitCompilationEntry;
1819 GPtrArray *in_flight_methods; //JitCompilationEntry*
1821 } JitCompilationData;
1823 static JitCompilationData compilation_data;
1824 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1827 mini_jit_init_job_control (void)
1829 mono_coop_mutex_init (&compilation_data.lock);
1830 compilation_data.in_flight_methods = g_ptr_array_new ();
1834 lock_compilation_data (void)
1836 mono_coop_mutex_lock (&compilation_data.lock);
1840 unlock_compilation_data (void)
1842 mono_coop_mutex_unlock (&compilation_data.lock);
1845 static JitCompilationEntry*
1846 find_method (MonoMethod *method, MonoDomain *domain)
1849 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1850 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1851 if (e->method == method && e->domain == domain)
1859 add_current_thread (MonoJitTlsData *jit_tls)
1861 ++jit_tls->active_jit_methods;
1865 unref_jit_entry (JitCompilationEntry *entry)
1868 if (entry->ref_count)
1870 if (entry->has_cond)
1871 mono_coop_cond_destroy (&entry->cond);
1876 * Returns true if this method waited successfully for another thread to JIT it
1879 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1881 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1882 JitCompilationEntry *entry;
1884 static gboolean inited;
1886 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1887 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1888 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1889 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1893 lock_compilation_data ();
1895 if (!(entry = find_method (method, domain))) {
1896 entry = g_new0 (JitCompilationEntry, 1);
1897 entry->method = method;
1898 entry->domain = domain;
1899 entry->compilation_count = entry->ref_count = 1;
1900 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1901 g_assert (find_method (method, domain) == entry);
1902 add_current_thread (jit_tls);
1904 unlock_compilation_data ();
1906 } else if (jit_tls->active_jit_methods > 0) {
1907 //We can't suspend the current thread if it's already JITing a method.
1908 //Dependency management is too compilated and we want to get rid of this anyways.
1909 ++entry->compilation_count;
1910 ++jit_methods_multiple;
1911 ++jit_tls->active_jit_methods;
1913 unlock_compilation_data ();
1916 ++jit_methods_waited;
1919 if (!entry->has_cond) {
1920 mono_coop_cond_init (&entry->cond);
1921 entry->has_cond = TRUE;
1925 ++entry->threads_waiting;
1927 g_assert (entry->has_cond);
1928 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
1929 --entry->threads_waiting;
1932 unref_jit_entry (entry);
1933 unlock_compilation_data ();
1936 ++jit_spurious_wakeups;
1943 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1945 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1947 lock_compilation_data ();
1949 g_assert (jit_tls->active_jit_methods > 0);
1950 --jit_tls->active_jit_methods;
1952 JitCompilationEntry *entry = find_method (method, target_domain);
1953 g_assert (entry); // It would be weird to fail
1956 if (entry->threads_waiting) {
1957 g_assert (entry->has_cond);
1958 mono_coop_cond_broadcast (&entry->cond);
1961 if (--entry->compilation_count == 0) {
1962 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1963 unref_jit_entry (entry);
1966 unlock_compilation_data ();
1971 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1973 MonoDomain *target_domain, *domain = mono_domain_get ();
1975 gpointer code = NULL, p;
1977 MonoJitICallInfo *callinfo = NULL;
1978 WrapperInfo *winfo = NULL;
1982 #ifdef ENABLE_INTERPRETER
1983 if (mono_use_interpreter && !jit_only) {
1984 code = mono_interp_create_method_pointer (method, error);
1991 /* Should be handled by the caller */
1992 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
1995 * ICALL wrappers are handled specially, since there is only one copy of them
1996 * shared by all appdomains.
1998 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1999 winfo = mono_marshal_get_wrapper_info (method);
2000 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2001 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2002 g_assert (callinfo);
2004 /* Must be domain neutral since there is only one copy */
2005 opt |= MONO_OPT_SHARED;
2007 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2008 opt &= ~MONO_OPT_SHARED;
2011 if (opt & MONO_OPT_SHARED)
2012 target_domain = mono_get_root_domain ();
2014 target_domain = domain;
2016 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2017 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2020 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2021 MonoGenericContext *ctx = NULL;
2022 if (method->is_inflated)
2023 ctx = mono_method_get_context (method);
2024 method = info->d.synchronized_inner.method;
2026 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2027 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2033 info = lookup_method (target_domain, method);
2035 /* We can't use a domain specific method in another domain */
2036 if (! ((domain != target_domain) && !info->domain_neutral)) {
2039 mono_jit_stats.methods_lookups++;
2040 vtable = mono_class_vtable_full (domain, method->klass, error);
2044 if (!mono_runtime_class_init_full (vtable, error))
2046 return mono_create_ftnptr (target_domain, info->code_start);
2050 #ifdef MONO_USE_AOT_COMPILER
2051 if (opt & MONO_OPT_AOT) {
2052 MonoDomain *domain = mono_domain_get ();
2054 mono_class_init (method->klass);
2056 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2059 if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
2061 * The suspend code needs to be able to lookup these methods by ip in async context,
2062 * so preload their jit info.
2064 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2069 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2070 * This is not a problem, since it will be initialized when the method is first
2071 * called by init_method ().
2073 if (!mono_llvm_only) {
2074 vtable = mono_class_vtable (domain, method->klass);
2076 if (!mono_runtime_class_init_full (vtable, error))
2085 if (!code && mono_llvm_only) {
2086 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2087 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2089 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2091 * These wrappers are only created for signatures which are in the program, but
2092 * sometimes we load methods too eagerly and have to create them even if they
2093 * will never be called.
2095 return no_gsharedvt_in_wrapper;
2101 if (wait_or_register_method_to_compile (method, target_domain))
2103 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2104 unregister_method_for_compile (method, target_domain);
2106 if (!mono_error_ok (error))
2109 if (!code && mono_llvm_only) {
2110 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2111 g_assert_not_reached ();
2117 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2121 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2123 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2127 p = mono_create_ftnptr (target_domain, code);
2130 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2131 mono_loader_lock ();
2133 if (!callinfo->wrapper) {
2134 callinfo->wrapper = p;
2135 mono_register_jit_icall_wrapper (callinfo, p);
2138 mono_loader_unlock ();
2145 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2149 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2154 * mono_jit_compile_method_jit_only:
2156 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2159 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2163 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2167 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2169 invalidated_delegate_trampoline (char *desc)
2171 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2172 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2178 * mono_jit_free_method:
2180 * Free all memory allocated by the JIT for METHOD.
2183 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2185 MonoJitDynamicMethodInfo *ji;
2186 gboolean destroy = TRUE;
2187 GHashTableIter iter;
2188 MonoJumpList *jlist;
2190 g_assert (method->dynamic);
2192 mono_domain_lock (domain);
2193 ji = mono_dynamic_code_hash_lookup (domain, method);
2194 mono_domain_unlock (domain);
2199 mono_debug_remove_method (method, domain);
2200 mono_lldb_remove_method (domain, method, ji);
2202 mono_domain_lock (domain);
2203 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2204 mono_domain_jit_code_hash_lock (domain);
2205 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2206 mono_domain_jit_code_hash_unlock (domain);
2207 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2209 /* requires the domain lock - took above */
2210 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2212 /* Remove jump targets in this method */
2213 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2214 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2215 GSList *tmp, *remove;
2218 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2219 guint8 *ip = (guint8 *)tmp->data;
2221 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2222 remove = g_slist_prepend (remove, tmp);
2224 for (tmp = remove; tmp; tmp = tmp->next) {
2225 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2227 g_slist_free (remove);
2229 mono_domain_unlock (domain);
2231 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2232 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2234 * Instead of freeing the code, change it to call an error routine
2235 * so people can fix their code.
2237 char *type = mono_type_full_name (&method->klass->byval_arg);
2238 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2241 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2247 * This needs to be done before freeing code_mp, since the code address is the
2248 * key in the table, so if we free the code_mp first, another thread can grab the
2249 * same code address and replace our entry in the table.
2251 mono_jit_info_table_remove (domain, ji->ji);
2254 mono_code_manager_destroy (ji->code_mp);
2259 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2261 MonoDomain *target_domain;
2264 if (default_opt & MONO_OPT_SHARED)
2265 target_domain = mono_get_root_domain ();
2267 target_domain = domain;
2269 info = lookup_method (target_domain, method);
2271 /* We can't use a domain specific method in another domain */
2272 if (! ((domain != target_domain) && !info->domain_neutral)) {
2273 mono_jit_stats.methods_lookups++;
2276 return info->code_start;
2285 static guint32 bisect_opt = 0;
2286 static GHashTable *bisect_methods_hash = NULL;
2289 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2292 char method_name [2048];
2295 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2296 g_assert (bisect_methods_hash);
2298 file = fopen (method_list_filename, "r");
2301 while (fgets (method_name, sizeof (method_name), file)) {
2302 size_t len = strlen (method_name);
2304 g_assert (method_name [len - 1] == '\n');
2305 method_name [len - 1] = 0;
2306 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2308 g_assert (feof (file));
2311 gboolean mono_do_single_method_regression = FALSE;
2312 guint32 mono_single_method_regression_opt = 0;
2313 MonoMethod *mono_current_single_method;
2314 GSList *mono_single_method_list;
2315 GHashTable *mono_single_method_hash;
2318 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2322 if (bisect_methods_hash) {
2323 char *name = mono_method_full_name (method, TRUE);
2324 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2327 return default_opt | bisect_opt;
2329 if (!mono_do_single_method_regression)
2331 if (!mono_current_single_method) {
2332 if (!mono_single_method_hash)
2333 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2334 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2335 g_hash_table_insert (mono_single_method_hash, method, method);
2336 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2340 if (method == mono_current_single_method)
2341 return mono_single_method_regression_opt;
2346 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2348 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2353 gpointer compiled_method;
2354 gpointer runtime_invoke;
2356 MonoDynCallInfo *dyn_call_info;
2357 MonoClass *ret_box_class;
2358 MonoMethodSignature *sig;
2359 gboolean gsharedvt_invoke;
2360 gpointer *wrapper_arg;
2361 } RuntimeInvokeInfo;
2363 static RuntimeInvokeInfo*
2364 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2367 RuntimeInvokeInfo *info;
2369 info = g_new0 (RuntimeInvokeInfo, 1);
2370 info->compiled_method = compiled_method;
2371 if (mono_llvm_only && method->string_ctor)
2372 info->sig = mono_marshal_get_string_ctor_signature (method);
2374 info->sig = mono_method_signature (method);
2376 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2377 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2378 if (!mono_error_ok (error))
2380 g_assert (info->vtable);
2382 MonoMethodSignature *sig = info->sig;
2386 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2387 * in full-aot mode, so we use a slower, but more generic wrapper if
2388 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2390 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2391 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2392 gboolean supported = TRUE;
2395 if (method->string_ctor)
2396 sig = mono_marshal_get_string_ctor_signature (method);
2398 for (i = 0; i < sig->param_count; ++i) {
2399 MonoType *t = sig->params [i];
2401 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2405 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2409 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2413 ret_type = sig->ret;
2414 switch (ret_type->type) {
2415 case MONO_TYPE_VOID:
2427 case MONO_TYPE_BOOLEAN:
2428 case MONO_TYPE_CHAR:
2431 info->ret_box_class = mono_class_from_mono_type (ret_type);
2434 info->ret_box_class = mono_defaults.int_class;
2436 case MONO_TYPE_STRING:
2437 case MONO_TYPE_CLASS:
2438 case MONO_TYPE_ARRAY:
2439 case MONO_TYPE_SZARRAY:
2440 case MONO_TYPE_OBJECT:
2442 case MONO_TYPE_GENERICINST:
2443 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2444 info->ret_box_class = mono_class_from_mono_type (ret_type);
2446 case MONO_TYPE_VALUETYPE:
2447 info->ret_box_class = mono_class_from_mono_type (ret_type);
2450 g_assert_not_reached ();
2454 if (!info->dyn_call_info) {
2455 if (mono_llvm_only) {
2456 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2457 g_assert_not_reached ();
2459 info->gsharedvt_invoke = TRUE;
2460 if (!callee_gsharedvt) {
2461 /* Invoke a gsharedvt out wrapper instead */
2462 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2463 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2465 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2466 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2468 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2469 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2470 g_free (wrapper_sig);
2472 info->compiled_method = mono_jit_compile_method (wrapper, error);
2473 if (!mono_error_ok (error)) {
2478 /* Gsharedvt methods can be invoked the same way */
2479 /* The out wrapper has the same signature as the compiled gsharedvt method */
2480 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2482 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2484 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2485 g_free (wrapper_sig);
2488 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2489 if (!mono_error_ok (error)) {
2499 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2501 MonoMethodSignature *sig = info->sig;
2502 MonoDomain *domain = mono_domain_get ();
2503 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2505 gpointer retval_ptr;
2506 guint8 retval [256];
2507 gpointer *param_refs;
2512 g_assert (info->gsharedvt_invoke);
2515 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2516 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2517 * signatures, so we only have to generate runtime invoke wrappers for these
2519 * This code also handles invocation of gsharedvt methods directly, no
2520 * out wrappers are used in that case.
2522 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2523 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2526 * The runtime invoke wrappers expects pointers to primitive types, so have to
2530 args [pindex ++] = &obj;
2531 if (sig->ret->type != MONO_TYPE_VOID) {
2532 retval_ptr = (gpointer)&retval;
2533 args [pindex ++] = &retval_ptr;
2535 for (i = 0; i < sig->param_count; ++i) {
2536 MonoType *t = sig->params [i];
2538 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2539 MonoClass *klass = mono_class_from_mono_type (t);
2540 guint8 *nullable_buf;
2543 size = mono_class_value_size (klass, NULL);
2544 nullable_buf = g_alloca (size);
2545 g_assert (nullable_buf);
2547 /* The argument pointed to by params [i] is either a boxed vtype or null */
2548 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2549 params [i] = nullable_buf;
2552 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2553 param_refs [i] = params [i];
2554 params [i] = &(param_refs [i]);
2556 args [pindex ++] = ¶ms [i];
2558 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2559 args [pindex ++] = &info->wrapper_arg;
2561 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2563 runtime_invoke (NULL, args, exc, info->compiled_method);
2567 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2568 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2570 return *(MonoObject**)retval;
2574 * mono_jit_runtime_invoke:
2575 * \param method: the method to invoke
2576 * \param obj: this pointer
2577 * \param params: array of parameter values.
2578 * \param exc: Set to the exception raised in the managed method.
2579 * \param error: error or caught exception object
2580 * If \p exc is NULL, \p error is thrown instead.
2581 * If coop is enabled, \p exc argument is ignored -
2582 * all exceptions are caught and propagated through \p error
2585 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2587 MonoMethod *invoke, *callee;
2588 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2589 MonoDomain *domain = mono_domain_get ();
2590 MonoJitDomainInfo *domain_info;
2591 RuntimeInvokeInfo *info, *info2;
2592 MonoJitInfo *ji = NULL;
2593 gboolean callee_gsharedvt = FALSE;
2595 #ifdef ENABLE_INTERPRETER
2596 if (mono_use_interpreter)
2597 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2602 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2603 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2607 domain_info = domain_jit_info (domain);
2609 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2612 if (mono_security_core_clr_enabled ()) {
2614 * This might be redundant since mono_class_vtable () already does this,
2615 * but keep it just in case for moonlight.
2617 mono_class_setup_vtable (method->klass);
2618 if (mono_class_has_failure (method->klass)) {
2619 mono_error_set_for_class_failure (error, method->klass);
2621 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2626 gpointer compiled_method;
2629 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2630 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2632 * Array Get/Set/Address methods. The JIT implements them using inline code
2633 * inside the runtime invoke wrappers, so no need to compile them.
2635 if (mono_aot_only) {
2637 * Call a wrapper, since the runtime invoke wrapper was not generated.
2639 MonoMethod *wrapper;
2641 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2642 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2650 compiled_method = mono_jit_compile_method (callee, error);
2651 if (!compiled_method) {
2652 g_assert (!mono_error_ok (error));
2656 if (mono_llvm_only) {
2657 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2658 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2659 if (callee_gsharedvt)
2660 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2663 if (!callee_gsharedvt)
2664 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2666 compiled_method = NULL;
2669 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2670 if (!mono_error_ok (error))
2673 mono_domain_lock (domain);
2674 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2675 mono_domain_unlock (domain);
2683 * We need this here because mono_marshal_get_runtime_invoke can place
2684 * the helper method in System.Object and not the target class.
2686 if (!mono_runtime_class_init_full (info->vtable, error)) {
2688 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2692 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2693 we always catch the exception and propagate it through the MonoError */
2694 gboolean catchExcInMonoError =
2695 (exc == NULL) && mono_threads_is_coop_enabled ();
2696 MonoObject *invoke_exc = NULL;
2697 if (catchExcInMonoError)
2700 /* The wrappers expect this to be initialized to NULL */
2704 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2705 if (info->dyn_call_info) {
2706 MonoMethodSignature *sig = mono_method_signature (method);
2708 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2711 guint8 retval [256];
2713 if (!dyn_runtime_invoke) {
2714 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2715 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2716 if (!mono_error_ok (error))
2720 /* Convert the arguments to the format expected by start_dyn_call () */
2721 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2724 args [pindex ++] = &obj;
2725 for (i = 0; i < sig->param_count; ++i) {
2726 MonoType *t = sig->params [i];
2729 args [pindex ++] = ¶ms [i];
2730 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2731 args [pindex ++] = ¶ms [i];
2733 args [pindex ++] = params [i];
2737 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2739 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2741 dyn_runtime_invoke (buf, exc, info->compiled_method);
2742 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2744 if (catchExcInMonoError && *exc != NULL) {
2745 mono_error_set_exception_instance (error, (MonoException*) *exc);
2749 if (info->ret_box_class)
2750 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2752 return *(MonoObject**)retval;
2758 if (mono_llvm_only) {
2759 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2763 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2765 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2767 if (catchExcInMonoError && *exc != NULL)
2768 mono_error_set_exception_instance (error, (MonoException*) *exc);
2777 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2780 * mini_llvmonly_initial_imt_tramp:
2782 * This function is called the first time a call is made through an IMT trampoline.
2783 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2786 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2788 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2793 mono_vtable_build_imt_slot (info->vtable, info->slot);
2795 imt = (gpointer*)info->vtable;
2796 imt -= MONO_IMT_SIZE;
2798 /* Return what the real IMT trampoline returns */
2799 ftndesc = imt [info->slot];
2802 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2803 /* Happens when the imt slot contains only a generic virtual method */
2805 return func ((gpointer *)ftndesc [1], imt_method);
2808 /* This is called indirectly through an imt slot. */
2810 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2814 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2815 while (arg [i] && arg [i] != imt_method)
2822 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2824 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2826 //g_assert (arg [0] == imt_method);
2831 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2833 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2834 if (arg [0] == imt_method)
2841 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2843 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2844 if (arg [0] == imt_method)
2846 else if (arg [2] == imt_method)
2853 * A version of the imt trampoline used for generic virtual/variant iface methods.
2854 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2855 * in the search table. The original JIT code had a 'fallback' trampoline it could
2856 * call, but we can't do that, so we just return NULL, and the compiled code
2860 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2864 while (arg [i] && arg [i] != imt_method)
2873 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2877 int i, index, real_count;
2878 gboolean virtual_generic = FALSE;
2881 * Create an array which is passed to the imt trampoline functions.
2882 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2886 for (i = 0; i < count; ++i) {
2887 MonoIMTCheckItem *item = imt_entries [i];
2889 if (item->is_equals)
2891 if (item->has_target_code)
2892 virtual_generic = TRUE;
2896 * Initialize all vtable entries reachable from this imt slot, so the compiled
2897 * code doesn't have to check it.
2899 for (i = 0; i < count; ++i) {
2900 MonoIMTCheckItem *item = imt_entries [i];
2903 if (!item->is_equals || item->has_target_code)
2905 vt_slot = item->value.vtable_slot;
2906 mono_init_vtable_slot (vtable, vt_slot);
2909 /* Save the entries into an array */
2910 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2912 for (i = 0; i < count; ++i) {
2913 MonoIMTCheckItem *item = imt_entries [i];
2915 if (!item->is_equals)
2918 g_assert (item->key);
2919 buf [(index * 2)] = item->key;
2920 if (item->has_target_code)
2921 buf [(index * 2) + 1] = item->value.target_code;
2923 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2926 buf [(index * 2)] = NULL;
2927 buf [(index * 2) + 1] = fail_tramp;
2930 * Return a function descriptor for a C function with 'buf' as its argument.
2931 * It will by called by JITted code.
2933 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2934 switch (real_count) {
2936 res [0] = mono_llvmonly_imt_tramp_1;
2939 res [0] = mono_llvmonly_imt_tramp_2;
2942 res [0] = mono_llvmonly_imt_tramp_3;
2945 res [0] = mono_llvmonly_imt_tramp;
2948 if (virtual_generic || fail_tramp)
2949 res [0] = mono_llvmonly_fallback_imt_tramp;
2955 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2957 MonoException *exc = NULL;
2959 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2960 MONO_SIG_HANDLER_GET_CONTEXT;
2962 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2964 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2966 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2967 if (mono_arch_is_int_overflow (ctx, info))
2969 * The spec says this throws ArithmeticException, but MS throws the derived
2970 * OverflowException.
2972 exc = mono_get_exception_overflow ();
2974 exc = mono_get_exception_divide_by_zero ();
2976 exc = mono_get_exception_divide_by_zero ();
2980 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
2983 mono_handle_native_crash ("SIGFPE", ctx, info);
2984 if (mono_do_crash_chaining) {
2985 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
2990 mono_arch_handle_exception (ctx, exc);
2993 MONO_EXIT_GC_UNSAFE_UNBALANCED;
2996 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
2998 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2999 MONO_SIG_HANDLER_GET_CONTEXT;
3001 if (mono_runtime_get_no_exec ())
3005 mono_handle_native_crash ("SIGILL", ctx, info);
3006 if (mono_do_crash_chaining) {
3007 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3011 g_assert_not_reached ();
3014 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3015 #define HAVE_SIG_INFO
3018 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3021 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3022 gpointer fault_addr = NULL;
3023 #ifdef HAVE_SIG_INFO
3024 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3028 MONO_SIG_HANDLER_GET_CONTEXT;
3030 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3031 if (mono_arch_is_single_step_event (info, ctx)) {
3032 mono_debugger_agent_single_step_event (ctx);
3034 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3035 mono_debugger_agent_breakpoint_hit (ctx);
3040 #if defined(HAVE_SIG_INFO)
3041 #if !defined(HOST_WIN32)
3042 fault_addr = info->si_addr;
3043 if (mono_aot_is_pagefault (info->si_addr)) {
3044 mono_aot_handle_pagefault (info->si_addr);
3049 /* The thread might no be registered with the runtime */
3050 if (!mono_domain_get () || !jit_tls) {
3051 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3053 mono_handle_native_crash ("SIGSEGV", ctx, info);
3054 if (mono_do_crash_chaining) {
3055 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3061 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3063 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3064 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3067 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3068 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3069 fault_addr = info->si_addr;
3070 if (fault_addr == NULL) {
3073 mono_sigctx_to_monoctx (ctx, &mctx);
3075 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3079 if (jit_tls->stack_size &&
3080 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3082 * The hard-guard page has been hit: there is not much we can do anymore
3083 * Print a hopefully clear message and abort.
3085 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3086 g_assert_not_reached ();
3088 /* The original handler might not like that it is executed on an altstack... */
3089 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3092 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3097 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3100 mono_handle_native_crash ("SIGSEGV", ctx, info);
3102 if (mono_do_crash_chaining) {
3103 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3108 mono_arch_handle_exception (ctx, NULL);
3112 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3115 MONO_SIG_HANDLER_GET_CONTEXT;
3117 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3119 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3121 mono_arch_handle_exception (ctx, exc);
3123 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3126 #ifndef DISABLE_REMOTING
3127 /* mono_jit_create_remoting_trampoline:
3128 * @method: pointer to the method info
3130 * Creates a trampoline which calls the remoting functions. This
3131 * is used in the vtable of transparent proxies.
3133 * Returns: a pointer to the newly created code
3136 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3139 guint8 *addr = NULL;
3143 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3144 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3148 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3149 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3150 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3153 addr = (guint8 *)mono_compile_method_checked (nm, error);
3154 return_val_if_nok (error, NULL);
3155 return mono_get_addr_from_ftnptr (addr);
3159 static G_GNUC_UNUSED void
3160 no_imt_trampoline (void)
3162 g_assert_not_reached ();
3165 static G_GNUC_UNUSED void
3166 no_vcall_trampoline (void)
3168 g_assert_not_reached ();
3171 static gpointer *vtable_trampolines;
3172 static int vtable_trampolines_size;
3175 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3177 int index = slot_index + MONO_IMT_SIZE;
3179 if (mono_llvm_only) {
3180 if (slot_index < 0) {
3181 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3182 // FIXME: Memory management
3183 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3184 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3187 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3189 mono_memory_barrier ();
3196 g_assert (slot_index >= - MONO_IMT_SIZE);
3197 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3199 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3203 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3204 while (new_size <= index)
3206 new_table = g_new0 (gpointer, new_size);
3208 if (vtable_trampolines)
3209 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3210 g_free (vtable_trampolines);
3211 mono_memory_barrier ();
3212 vtable_trampolines = (void **)new_table;
3213 vtable_trampolines_size = new_size;
3218 if (!vtable_trampolines [index])
3219 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3220 return vtable_trampolines [index];
3224 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3226 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3230 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3235 gpointer *imt = (gpointer*)vt;
3236 imt -= MONO_IMT_SIZE;
3238 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3242 is_callee_gsharedvt_variable (gpointer addr)
3245 gboolean callee_gsharedvt;
3247 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3249 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3250 if (callee_gsharedvt)
3251 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3252 return callee_gsharedvt;
3256 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3258 gpointer arg = NULL;
3260 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3261 arg = mini_method_get_rgctx (method);
3264 * Avoid adding gsharedvt in wrappers since they might not exist if
3265 * this delegate is called through a gsharedvt delegate invoke wrapper.
3266 * Instead, encode that the method is gsharedvt in del->extra_arg,
3267 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3269 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3270 g_assert ((((mgreg_t)arg) & 1) == 0);
3271 arg = (gpointer)(((mgreg_t)arg) | 1);
3277 mini_init_delegate (MonoDelegate *del)
3280 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3281 #ifdef ENABLE_INTERPRETER
3282 if (mono_use_interpreter)
3283 mono_interp_init_delegate (del);
3288 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3292 abs_offset = offset;
3294 abs_offset = - abs_offset;
3295 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3299 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3301 gboolean is_virtual_generic, is_interface, load_imt_reg;
3304 static guint8 **cache = NULL;
3305 static int cache_size = 0;
3310 if (MONO_TYPE_ISSTRUCT (sig->ret))
3313 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3314 is_interface = mono_class_is_interface (method->klass);
3315 load_imt_reg = is_virtual_generic || is_interface;
3318 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3320 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3322 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3323 g_assert (idx >= 0);
3325 /* Resize the cache to idx + 1 */
3326 if (cache_size < idx + 1) {
3328 if (cache_size < idx + 1) {
3330 int new_cache_size = idx + 1;
3332 new_cache = g_new0 (guint8*, new_cache_size);
3334 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3337 mono_memory_barrier ();
3339 cache_size = new_cache_size;
3347 /* FIXME Support more cases */
3348 if (mono_aot_only) {
3349 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3350 g_assert (cache [idx]);
3352 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3358 * mini_parse_debug_option:
3359 * @option: The option to parse.
3361 * Parses debug options for the mono runtime. The options are the same as for
3362 * the MONO_DEBUG environment variable.
3366 mini_parse_debug_option (const char *option)
3368 if (!strcmp (option, "handle-sigint"))
3369 debug_options.handle_sigint = TRUE;
3370 else if (!strcmp (option, "keep-delegates"))
3371 debug_options.keep_delegates = TRUE;
3372 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3373 debug_options.reverse_pinvoke_exceptions = TRUE;
3374 else if (!strcmp (option, "collect-pagefault-stats"))
3375 debug_options.collect_pagefault_stats = TRUE;
3376 else if (!strcmp (option, "break-on-unverified"))
3377 debug_options.break_on_unverified = TRUE;
3378 else if (!strcmp (option, "no-gdb-backtrace"))
3379 debug_options.no_gdb_backtrace = TRUE;
3380 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3381 debug_options.suspend_on_native_crash = TRUE;
3382 else if (!strcmp (option, "suspend-on-exception"))
3383 debug_options.suspend_on_exception = TRUE;
3384 else if (!strcmp (option, "suspend-on-unhandled"))
3385 debug_options.suspend_on_unhandled = TRUE;
3386 else if (!strcmp (option, "dont-free-domains"))
3387 mono_dont_free_domains = TRUE;
3388 else if (!strcmp (option, "dyn-runtime-invoke"))
3389 debug_options.dyn_runtime_invoke = TRUE;
3390 else if (!strcmp (option, "gdb"))
3391 debug_options.gdb = TRUE;
3392 else if (!strcmp (option, "lldb"))
3393 debug_options.lldb = TRUE;
3394 else if (!strcmp (option, "explicit-null-checks"))
3395 debug_options.explicit_null_checks = TRUE;
3396 else if (!strcmp (option, "gen-seq-points"))
3397 debug_options.gen_sdb_seq_points = TRUE;
3398 else if (!strcmp (option, "gen-compact-seq-points"))
3399 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3400 else if (!strcmp (option, "no-compact-seq-points"))
3401 debug_options.no_seq_points_compact_data = TRUE;
3402 else if (!strcmp (option, "single-imm-size"))
3403 debug_options.single_imm_size = TRUE;
3404 else if (!strcmp (option, "init-stacks"))
3405 debug_options.init_stacks = TRUE;
3406 else if (!strcmp (option, "casts"))
3407 debug_options.better_cast_details = TRUE;
3408 else if (!strcmp (option, "soft-breakpoints"))
3409 debug_options.soft_breakpoints = TRUE;
3410 else if (!strcmp (option, "check-pinvoke-callconv"))
3411 debug_options.check_pinvoke_callconv = TRUE;
3412 else if (!strcmp (option, "use-fallback-tls"))
3413 debug_options.use_fallback_tls = TRUE;
3414 else if (!strcmp (option, "debug-domain-unload"))
3415 mono_enable_debug_domain_unload (TRUE);
3416 else if (!strcmp (option, "partial-sharing"))
3417 mono_set_partial_sharing_supported (TRUE);
3418 else if (!strcmp (option, "align-small-structs"))
3419 mono_align_small_structs = TRUE;
3420 else if (!strcmp (option, "native-debugger-break"))
3421 debug_options.native_debugger_break = TRUE;
3422 else if (!strcmp (option, "disable_omit_fp"))
3423 debug_options.disable_omit_fp = TRUE;
3431 mini_parse_debug_options (void)
3433 char *options = g_getenv ("MONO_DEBUG");
3434 gchar **args, **ptr;
3439 args = g_strsplit (options, ",", -1);
3442 for (ptr = args; ptr && *ptr; ptr++) {
3443 const char *arg = *ptr;
3445 if (!mini_parse_debug_option (arg)) {
3446 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3447 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");
3456 mini_get_debug_options (void)
3458 return &debug_options;
3462 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3464 #if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3467 gpointer* desc = NULL;
3469 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3472 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
3476 # elif defined(__ppc64__) || defined(__powerpc64__)
3478 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3484 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3490 mini_get_addr_from_ftnptr (gpointer descr)
3492 #if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3493 return *(gpointer*)descr;
3500 register_jit_stats (void)
3502 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3503 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3504 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3505 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3506 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3507 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3508 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);
3509 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3510 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3511 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3512 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3513 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3514 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3515 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3516 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3517 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3518 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3519 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3520 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3521 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3522 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3523 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3524 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3525 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3526 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3527 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3528 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3529 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3530 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3531 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3532 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3533 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3534 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3535 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3536 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3537 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3538 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3539 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3540 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3541 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3542 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3543 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3544 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3545 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3546 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3547 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3548 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3549 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3550 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3551 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3552 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3553 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3554 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3555 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3556 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3557 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3558 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3559 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3560 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3561 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3562 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3565 static void runtime_invoke_info_free (gpointer value);
3568 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3570 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3571 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3573 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3577 class_method_pair_hash (gconstpointer data)
3579 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3581 return (gsize)pair->klass ^ (gsize)pair->method;
3585 mini_create_jit_domain_info (MonoDomain *domain)
3587 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3589 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3590 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3591 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3592 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3593 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3594 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3595 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3596 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3597 mono_jit_code_hash_init (&info->interp_code_hash);
3599 domain->runtime_info = info;
3603 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3605 MonoJumpList *jlist = (MonoJumpList *)value;
3606 g_slist_free (jlist->list);
3610 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3612 GSList *list = (GSList *)value;
3613 g_slist_free (list);
3617 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3619 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3620 mono_code_manager_destroy (di->code_mp);
3625 runtime_invoke_info_free (gpointer value)
3627 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3629 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3630 if (info->dyn_call_info)
3631 mono_arch_dyn_call_free (info->dyn_call_info);
3637 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3639 g_slist_free (value);
3643 mini_free_jit_domain_info (MonoDomain *domain)
3645 MonoJitDomainInfo *info = domain_jit_info (domain);
3647 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3648 g_hash_table_destroy (info->jump_target_hash);
3649 if (info->jump_target_got_slot_hash) {
3650 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3651 g_hash_table_destroy (info->jump_target_got_slot_hash);
3653 if (info->dynamic_code_hash) {
3654 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3655 g_hash_table_destroy (info->dynamic_code_hash);
3657 if (info->method_code_hash)
3658 g_hash_table_destroy (info->method_code_hash);
3659 g_hash_table_destroy (info->jump_trampoline_hash);
3660 g_hash_table_destroy (info->jit_trampoline_hash);
3661 g_hash_table_destroy (info->delegate_trampoline_hash);
3662 if (info->static_rgctx_trampoline_hash)
3663 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3664 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3665 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3666 g_hash_table_destroy (info->seq_points);
3667 g_hash_table_destroy (info->arch_seq_points);
3668 if (info->agent_info)
3669 mono_debugger_agent_free_domain_info (domain);
3670 if (info->gsharedvt_arg_tramp_hash)
3671 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3672 if (info->llvm_jit_callees) {
3673 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3674 g_hash_table_destroy (info->llvm_jit_callees);
3676 mono_internal_hash_table_destroy (&info->interp_code_hash);
3678 mono_llvm_free_domain_info (domain);
3681 g_free (domain->runtime_info);
3682 domain->runtime_info = NULL;
3685 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3688 code_manager_chunk_new (void *chunk, int size)
3690 mono_arch_code_chunk_new (chunk, size);
3694 code_manager_chunk_destroy (void *chunk)
3696 mono_arch_code_chunk_destroy (chunk);
3703 llvm_init_inner (void)
3705 if (!mono_llvm_load (NULL))
3716 * Load and initialize LLVM support.
3717 * Return TRUE on success.
3720 mini_llvm_init (void)
3723 static gboolean llvm_inited;
3724 static gboolean init_result;
3726 mono_loader_lock_if_inited ();
3728 init_result = llvm_init_inner ();
3731 mono_loader_unlock_if_inited ();
3739 mini_profiler_enable_with_options (const char* profile_options)
3741 mini_enable_profiler = TRUE;
3742 mini_profiler_options = g_strdup (profile_options);
3746 mini_init (const char *filename, const char *runtime_version)
3750 MonoRuntimeCallbacks callbacks;
3751 MonoThreadInfoRuntimeCallbacks ticallbacks;
3752 MonoCodeManagerCallbacks code_manager_callbacks;
3754 MONO_VES_INIT_BEGIN ();
3756 CHECKED_MONO_INIT ();
3758 #if defined(__linux__) && !defined(__native_client__)
3759 if (access ("/proc/self/maps", F_OK) != 0) {
3760 g_print ("Mono requires /proc to be mounted.\n");
3765 #ifdef ENABLE_INTERPRETER
3766 mono_interp_init ();
3769 mono_os_mutex_init_recursive (&jit_mutex);
3771 mono_cross_helpers_run ();
3773 mono_counters_init ();
3777 mini_jit_init_job_control ();
3779 /* Happens when using the embedding interface */
3780 if (!default_opt_set)
3781 default_opt = mono_parse_default_optimizations (NULL);
3783 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3785 mono_set_generic_sharing_vt_supported (TRUE);
3788 mono_set_generic_sharing_vt_supported (TRUE);
3791 mono_tls_init_runtime_keys ();
3793 if (!global_codeman)
3794 global_codeman = mono_code_manager_new ();
3796 memset (&callbacks, 0, sizeof (callbacks));
3797 callbacks.create_ftnptr = mini_create_ftnptr;
3798 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3799 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3800 callbacks.set_cast_details = mono_set_cast_details;
3801 callbacks.debug_log = mono_debugger_agent_debug_log;
3802 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3803 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3804 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3805 callbacks.imt_entry_inited = mini_imt_entry_inited;
3806 callbacks.init_delegate = mini_init_delegate;
3807 #define JIT_INVOKE_WORKS
3808 #ifdef JIT_INVOKE_WORKS
3809 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3811 #define JIT_TRAMPOLINES_WORK
3812 #ifdef JIT_TRAMPOLINES_WORK
3813 callbacks.compile_method = mono_jit_compile_method;
3814 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3815 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3816 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3817 callbacks.free_method = mono_jit_free_method;
3818 #ifndef DISABLE_REMOTING
3819 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3823 mono_install_callbacks (&callbacks);
3825 memset (&ticallbacks, 0, sizeof (ticallbacks));
3826 ticallbacks.setup_async_callback = mono_setup_async_callback;
3827 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3828 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3829 ticallbacks.thread_state_init = mono_thread_state_init;
3832 mono_w32handle_init ();
3835 mono_threads_runtime_init (&ticallbacks);
3837 if (g_hasenv ("MONO_DEBUG")) {
3838 mini_parse_debug_options ();
3841 mono_code_manager_init ();
3843 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3844 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3845 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3846 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3848 mono_code_manager_install_callbacks (&code_manager_callbacks);
3852 mono_arch_cpu_init ();
3856 mono_unwind_init ();
3858 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3859 mono_lldb_init ("");
3860 mono_dont_free_domains = TRUE;
3863 #ifdef XDEBUG_ENABLED
3864 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3866 mono_xdebug_init (mono_xdebug);
3867 g_free (mono_xdebug);
3868 /* So methods for multiple domains don't have the same address */
3869 mono_dont_free_domains = TRUE;
3870 mono_using_xdebug = TRUE;
3871 } else if (mini_get_debug_options ()->gdb) {
3872 mono_xdebug_init ((char*)"gdb");
3873 mono_dont_free_domains = TRUE;
3874 mono_using_xdebug = TRUE;
3879 if (mono_use_llvm) {
3880 if (!mono_llvm_load (NULL)) {
3881 mono_use_llvm = FALSE;
3882 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3889 mono_trampolines_init ();
3891 if (default_opt & MONO_OPT_AOT)
3894 mono_debugger_agent_init ();
3896 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3897 mono_set_generic_sharing_supported (TRUE);
3900 mono_threads_signals_init ();
3902 #ifndef MONO_CROSS_COMPILE
3903 mono_runtime_install_handlers ();
3905 mono_threads_install_cleanup (mini_thread_cleanup);
3907 #ifdef JIT_TRAMPOLINES_WORK
3908 mono_install_create_domain_hook (mini_create_jit_domain_info);
3909 mono_install_free_domain_hook (mini_free_jit_domain_info);
3911 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3912 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3913 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3915 if (mini_profiler_enabled ()) {
3916 mono_profiler_load (mini_profiler_get_options ());
3917 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3920 if (debug_options.collect_pagefault_stats)
3921 mono_aot_set_make_unreadable (TRUE);
3923 if (runtime_version)
3924 domain = mono_init_version (filename, runtime_version);
3926 domain = mono_init_from_assembly (filename, filename);
3928 if (mono_aot_only) {
3929 /* This helps catch code allocation requests */
3930 mono_code_manager_set_read_only (domain->code_mp);
3931 mono_marshal_use_aot_wrappers (TRUE);
3934 if (mono_llvm_only) {
3935 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3936 mono_set_always_build_imt_trampolines (TRUE);
3937 } else if (mono_aot_only) {
3938 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3940 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3943 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3944 mono_arch_finish_init ();
3948 /* This must come after mono_init () in the aot-only case */
3949 mono_exceptions_init ();
3951 /* This should come after mono_init () too */
3955 mono_create_helper_signatures ();
3958 register_jit_stats ();
3960 #define JIT_CALLS_WORK
3961 #ifdef JIT_CALLS_WORK
3962 /* Needs to be called here since register_jit_icall depends on it */
3963 mono_marshal_init ();
3965 mono_arch_register_lowlevel_calls ();
3969 mono_generic_sharing_init ();
3972 #ifdef MONO_ARCH_SIMD_INTRINSICS
3973 mono_simd_intrinsics_init ();
3976 mono_tasklets_init ();
3978 register_trampolines (domain);
3980 if (mono_compile_aot)
3982 * Avoid running managed code when AOT compiling, since the platform
3983 * might only support aot-only execution.
3985 mono_runtime_set_no_exec (TRUE);
3987 mono_mem_account_register_counters ();
3989 #define JIT_RUNTIME_WORKS
3990 #ifdef JIT_RUNTIME_WORKS
3991 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
3992 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
3993 mono_error_assert_ok (&error);
3994 mono_thread_attach (domain);
3997 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
3998 mono_runtime_setup_stat_profiler ();
4000 mono_profiler_runtime_initialized ();
4002 MONO_VES_INIT_END ();
4008 register_icalls (void)
4010 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4011 ves_icall_get_frame_info);
4012 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4013 ves_icall_get_trace);
4014 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4015 mono_runtime_install_handlers);
4016 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4017 mono_runtime_cleanup_handlers);
4019 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4020 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4021 mono_debugger_agent_unhandled_exception);
4025 * It's important that we pass `TRUE` as the last argument here, as
4026 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4027 * *did* emit a wrapper, we'd be looking at infinite recursion since
4028 * the wrapper would call the icall which would call the wrapper and
4031 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4032 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4034 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4035 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4036 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4037 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4038 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4039 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4041 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4042 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4043 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4044 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4045 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4046 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4047 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4048 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4049 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4051 // FIXME: This is broken
4052 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4055 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4056 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4057 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4058 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4059 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4060 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4062 #if defined(__native_client__) || defined(__native_client_codegen__)
4063 register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
4066 if (mono_threads_is_coop_enabled ())
4067 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4069 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4070 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4071 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4072 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4073 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4074 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4076 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4077 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4078 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4081 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4082 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4083 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4084 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4087 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4088 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4089 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4090 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4091 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4094 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4095 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4098 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4099 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4100 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4103 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4104 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4107 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4108 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4109 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4110 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4111 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4112 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4113 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4116 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4117 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4118 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4121 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4122 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);
4124 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4125 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4127 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4128 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4130 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4131 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);
4133 #ifdef MONO_ARCH_EMULATE_FREM
4134 #if !defined(__native_client__)
4135 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4136 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4138 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
4142 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4143 if (mono_arch_is_soft_float ()) {
4144 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4145 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4146 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4147 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4148 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4149 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4150 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4151 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4152 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4153 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4154 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4155 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4157 #if SIZEOF_VOID_P == 4
4158 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4161 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4162 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4163 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4164 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4165 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4166 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4167 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4168 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4169 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4170 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4172 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4173 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4174 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4175 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4176 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4178 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4179 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4180 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4181 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4184 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4186 #ifdef COMPRESSED_INTERFACE_BITMAP
4187 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4190 #if SIZEOF_REGISTER == 4
4191 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4193 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4196 /* other jit icalls */
4197 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4198 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4199 "ptr ptr ptr", FALSE);
4200 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4201 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4202 "ptr ptr ptr ptr", FALSE);
4203 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4204 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4205 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4206 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4207 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4208 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4209 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4210 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4211 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4212 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4213 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4214 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4215 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4216 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4217 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4218 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4219 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4220 register_icall (mono_break, "mono_break", NULL, TRUE);
4221 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4222 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4223 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4224 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4225 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4226 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4227 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4228 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4229 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4230 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4231 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4233 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int");
4235 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4236 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4237 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4238 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4239 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4241 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4243 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4244 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4245 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4246 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4248 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4249 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4250 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4251 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4252 /* This needs a wrapper so it can have a preserveall cconv */
4253 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4254 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4255 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4256 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4257 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4258 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4259 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4261 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4262 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4263 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4264 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4267 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4269 /* Register tls icalls */
4270 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4271 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4272 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4273 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4274 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4275 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4276 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4277 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4278 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4279 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4282 MonoJitStats mono_jit_stats = {0};
4285 print_jit_stats (void)
4287 if (mono_jit_stats.enabled) {
4288 g_print ("Mono Jit statistics\n");
4289 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4290 mono_jit_stats.max_ratio_method);
4291 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4292 mono_jit_stats.biggest_method);
4294 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4295 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4296 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4297 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4298 g_print ("Methods: %ld\n", mono_stats.method_count);
4299 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4300 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4301 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4303 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4304 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4305 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4307 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4308 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4309 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4310 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4312 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4313 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4314 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4315 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4316 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4317 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4318 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4319 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4321 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4322 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4323 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4325 g_free (mono_jit_stats.max_ratio_method);
4326 mono_jit_stats.max_ratio_method = NULL;
4327 g_free (mono_jit_stats.biggest_method);
4328 mono_jit_stats.biggest_method = NULL;
4333 mini_cleanup (MonoDomain *domain)
4335 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4336 mono_runtime_shutdown_stat_profiler ();
4339 cominterop_release_all_rcws ();
4342 #ifndef MONO_CROSS_COMPILE
4344 * mono_domain_finalize () needs to be called early since it needs the
4345 * execution engine still fully working (it may invoke managed finalizers).
4347 mono_domain_finalize (domain, 2000);
4350 /* This accesses metadata so needs to be called before runtime shutdown */
4353 #ifndef MONO_CROSS_COMPILE
4354 mono_runtime_cleanup (domain);
4357 mono_threadpool_cleanup ();
4359 mono_profiler_shutdown ();
4361 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4363 mono_icall_cleanup ();
4365 mono_runtime_cleanup_handlers ();
4367 #ifndef MONO_CROSS_COMPILE
4368 mono_domain_free (domain, TRUE);
4373 mono_llvm_cleanup ();
4376 mono_aot_cleanup ();
4378 mono_trampolines_cleanup ();
4380 mono_unwind_cleanup ();
4382 mono_code_manager_destroy (global_codeman);
4383 g_free (vtable_trampolines);
4385 mini_jit_cleanup ();
4387 mono_tramp_info_cleanup ();
4389 mono_arch_cleanup ();
4391 mono_generic_sharing_cleanup ();
4395 mono_trace_cleanup ();
4397 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4399 if (mono_inject_async_exc_method)
4400 mono_method_desc_free (mono_inject_async_exc_method);
4402 mono_tls_free_keys ();
4404 mono_os_mutex_destroy (&jit_mutex);
4406 mono_code_manager_cleanup ();
4409 mono_w32handle_cleanup ();
4414 mono_set_defaults (int verbose_level, guint32 opts)
4416 mini_verbose = verbose_level;
4417 mono_set_optimizations (opts);
4421 mono_disable_optimizations (guint32 opts)
4423 default_opt &= ~opts;
4427 mono_set_optimizations (guint32 opts)
4430 default_opt_set = TRUE;
4431 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4432 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4435 mono_set_generic_sharing_vt_supported (TRUE);
4440 mono_set_verbose_level (guint32 level)
4442 mini_verbose = level;
4446 * mono_get_runtime_build_info:
4447 * The returned string is owned by the caller. The returned string
4448 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4449 * \returns the runtime version + build date in string format.
4452 mono_get_runtime_build_info (void)
4454 if (mono_build_date)
4455 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4457 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4461 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4463 GHashTable *assemblies = (GHashTable*)user_data;
4464 MonoImage *image = mono_assembly_get_image (ass);
4465 MonoMethod *method, *invoke;
4468 if (g_hash_table_lookup (assemblies, ass))
4471 g_hash_table_insert (assemblies, ass, ass);
4473 if (mini_verbose > 0)
4474 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4476 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4479 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4481 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4484 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4486 if (method->is_generic || mono_class_is_gtd (method->klass))
4490 if (mini_verbose > 1) {
4491 char * desc = mono_method_full_name (method, TRUE);
4492 g_print ("Compiling %d %s\n", count, desc);
4495 mono_compile_method_checked (method, &error);
4496 if (!is_ok (&error)) {
4497 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4500 if (strcmp (method->name, "Finalize") == 0) {
4501 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4502 mono_compile_method_checked (invoke, &error);
4503 mono_error_assert_ok (&error);
4505 #ifndef DISABLE_REMOTING
4506 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4507 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4508 mono_compile_method_checked (invoke, &error);
4509 mono_error_assert_ok (&error);
4514 /* Load and precompile referenced assemblies as well */
4515 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4516 mono_assembly_load_reference (image, i);
4517 if (image->references [i])
4518 mono_precompile_assembly (image->references [i], assemblies);
4522 void mono_precompile_assemblies ()
4524 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4526 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4528 g_hash_table_destroy (assemblies);
4533 * Have to export this for AOT.
4536 mono_personality (void)
4539 g_assert_not_reached ();
4542 // Custom handlers currently only implemented by Windows.
4545 mono_runtime_install_custom_handlers (const char *handlers)
4551 mono_runtime_install_custom_handlers_usage (void)
4554 "Custom Handlers:\n"
4555 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4556 " separated list of available handlers to install.\n"
4558 "No handlers supported on current platform.\n");
4560 #endif /* HOST_WIN32 */