3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include "mono/metadata/profiler.h"
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/utils/mono-math.h>
55 #include <mono/utils/mono-compiler.h>
56 #include <mono/utils/mono-counters.h>
57 #include <mono/utils/mono-error-internals.h>
58 #include <mono/utils/mono-logger-internals.h>
59 #include <mono/utils/mono-mmap.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-tls.h>
62 #include <mono/utils/mono-hwcap.h>
63 #include <mono/utils/dtrace.h>
64 #include <mono/utils/mono-signal-handler.h>
65 #include <mono/utils/mono-threads.h>
66 #include <mono/utils/mono-threads-coop.h>
67 #include <mono/utils/checked-build.h>
68 #include <mono/utils/mono-proclib.h>
69 #include <mono/metadata/w32handle.h>
70 #include <mono/metadata/threadpool.h>
73 #include "seq-points.h"
80 #include "jit-icalls.h"
83 #include "mini-llvm.h"
84 #include "debugger-agent.h"
87 #ifdef MONO_ARCH_LLVM_SUPPORTED
89 #include "mini-llvm-cpp.h"
94 #ifdef ENABLE_INTERPRETER
95 #include "interp/interp.h"
98 static guint32 default_opt
= 0;
99 static gboolean default_opt_set
= FALSE
;
101 gboolean mono_compile_aot
= FALSE
;
102 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
103 gboolean mono_aot_only
= FALSE
;
104 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
105 gboolean mono_llvm_only
= FALSE
;
106 MonoAotMode mono_aot_mode
= MONO_AOT_MODE_NONE
;
108 const char *mono_build_date
;
109 gboolean mono_do_signal_chaining
;
110 gboolean mono_do_crash_chaining
;
111 int mini_verbose
= 0;
114 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
115 * it can load AOT code compiled by LLVM.
117 gboolean mono_use_llvm
= FALSE
;
119 gboolean mono_use_interpreter
= FALSE
;
121 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
122 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
123 static mono_mutex_t jit_mutex
;
125 static MonoCodeManager
*global_codeman
;
127 MonoDebugOptions debug_options
;
129 #ifdef VALGRIND_JIT_REGISTER_MAP
130 int valgrind_register
;
132 GList
* mono_aot_paths
;
134 static gboolean mini_enable_profiler
= FALSE
;
135 static char* mini_profiler_options
= NULL
;
137 static GSList
*tramp_infos
;
139 static void register_icalls (void);
141 static gboolean
mini_profiler_enabled (void) { return mini_enable_profiler
; }
142 static const char* mini_profiler_get_options (void) { return mini_profiler_options
; }
145 mono_running_on_valgrind (void)
148 if (RUNNING_ON_VALGRIND
){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register
= TRUE
;
164 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
166 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
169 ud
->method
= (MonoMethod
*)key
;
173 G_GNUC_UNUSED
static char*
174 get_method_from_ip (void *ip
)
180 MonoDomain
*domain
= mono_domain_get ();
181 MonoDebugSourceLocation
*location
;
182 FindTrampUserData user_data
;
185 domain
= mono_get_root_domain ();
187 ji
= mono_jit_info_table_find_internal (domain
, (char *)ip
, TRUE
, TRUE
);
190 user_data
.method
= NULL
;
191 mono_domain_lock (domain
);
192 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
193 mono_domain_unlock (domain
);
194 if (user_data
.method
) {
195 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
196 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
202 } else if (ji
->is_trampoline
) {
203 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ((MonoTrampInfo
*)ji
->d
.tramp_info
)->name
);
207 method
= jinfo_get_method (ji
);
208 method_name
= mono_method_full_name (method
, TRUE
);
209 /* FIXME: unused ? */
210 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
212 res
= g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name
, method
, (int)((char*)ip
- (char*)ji
->code_start
), ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, domain
, domain
->friendly_name
);
214 mono_debug_free_source_location (location
);
215 g_free (method_name
);
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
235 return get_method_from_ip (ip
);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
250 mono_print_method_from_ip (void *ip
)
254 MonoDebugSourceLocation
*source
;
255 MonoDomain
*domain
= mono_domain_get ();
256 MonoDomain
*target_domain
= mono_domain_get ();
257 FindTrampUserData user_data
;
258 MonoGenericSharingContext
*gsctx
;
259 const char *shared_type
;
262 domain
= mono_get_root_domain ();
263 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
264 if (ji
&& ji
->is_trampoline
) {
265 MonoTrampInfo
*tinfo
= (MonoTrampInfo
*)ji
->d
.tramp_info
;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
273 user_data
.method
= NULL
;
274 mono_domain_lock (domain
);
275 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
276 mono_domain_unlock (domain
);
278 if (user_data
.method
) {
279 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
280 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
285 g_print ("No method at %p\n", ip
);
289 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
290 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
292 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
295 if (gsctx
->is_gsharedvt
)
296 shared_type
= "gsharedvt ";
298 shared_type
= "gshared ";
301 g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip
, (int)((char*)ip
- (char*)ji
->code_start
), shared_type
, method
, ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, target_domain
, target_domain
->friendly_name
);
304 g_print ("%s:%d\n", source
->source_file
, source
->row
);
307 mono_debug_free_source_location (source
);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
321 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
331 cmethod
= jinfo_get_method (caller
);
332 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
333 (strstr (cmethod
->name
, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size
)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman
) {
354 /* This can happen during startup */
355 global_codeman
= mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman
, size
);
360 ptr
= mono_code_manager_reserve (global_codeman
, size
);
366 /* The callback shouldn't take any locks */
368 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
371 mono_code_manager_foreach (global_codeman
, func
, user_data
);
375 #if defined(__native_client_codegen__) && defined(__native_client__)
379 #ifdef __native_client_gc__
380 __nacl_suspend_thread_if_needed();
383 #endif /* __native_client__ */
386 * mono_create_unwind_op:
388 * Create an unwind op with the given parameters.
391 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
393 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
404 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
406 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
409 res
->has_context
= context
!= NULL
;
411 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
417 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
419 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
423 * mono_tramp_info_create:
425 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
426 * of JI, and UNWIND_OPS.
429 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
431 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
433 info
->name
= g_strdup ((char*)name
);
435 info
->code_size
= code_size
;
437 info
->unwind_ops
= unwind_ops
;
443 mono_tramp_info_free (MonoTrampInfo
*info
)
448 mono_free_unwind_info (info
->unwind_ops
);
449 if (info
->owns_uw_info
)
450 g_free (info
->uw_info
);
455 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
459 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
460 mono_jit_info_init (ji
, NULL
, info
->code
, info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
461 ji
->d
.tramp_info
= info
;
462 ji
->is_trampoline
= TRUE
;
464 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
466 mono_jit_info_table_add (domain
, ji
);
470 * mono_tramp_info_register:
472 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
477 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
485 domain
= mono_get_root_domain ();
487 copy
= g_new0 (MonoTrampInfo
, 1);
488 copy
->code
= info
->code
;
489 copy
->code_size
= info
->code_size
;
490 copy
->name
= g_strdup (info
->name
);
492 if (info
->unwind_ops
) {
493 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
494 copy
->owns_uw_info
= TRUE
;
496 /* Trampolines from aot have the unwind ops already encoded */
497 copy
->uw_info
= info
->uw_info
;
498 copy
->uw_info_len
= info
->uw_info_len
;
502 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
505 mono_save_trampoline_xdebug_info (info
);
506 mono_lldb_save_trampoline_info (info
);
508 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
510 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
513 /* Only register trampolines that have unwind infos */
514 if (mono_get_root_domain () && copy
->uw_info
)
515 register_trampoline_jit_info (domain
, copy
);
517 if (mono_jit_map_is_enabled ())
518 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
520 mono_tramp_info_free (info
);
524 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
526 mono_tramp_info_register_internal (info
, domain
, FALSE
);
530 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
532 mono_tramp_info_register_internal (info
, domain
, TRUE
);
536 mono_tramp_info_cleanup (void)
540 for (l
= tramp_infos
; l
; l
= l
->next
) {
541 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
543 mono_tramp_info_free (info
);
545 g_slist_free (tramp_infos
);
548 /* Register trampolines created before the root domain was created in the jit info tables */
550 register_trampolines (MonoDomain
*domain
)
554 for (l
= tramp_infos
; l
; l
= l
->next
) {
555 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
557 register_trampoline_jit_info (domain
, info
);
561 G_GNUC_UNUSED
static void
567 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
568 * Set a breakpoint in break_count () to break the last time <x> is done.
570 G_GNUC_UNUSED gboolean
571 mono_debug_count (void)
573 static int count
= 0;
574 static gboolean inited
;
580 value
= g_getenv ("COUNT");
587 int int_val
= atoi (value
);
590 if (count
== int_val
)
600 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
605 gconstpointer trampoline
;
606 MonoDomain
*domain
= mono_get_root_domain ();
607 gboolean check_exc
= TRUE
;
609 if (callinfo
->wrapper
)
610 return callinfo
->wrapper
;
612 if (callinfo
->trampoline
)
613 return callinfo
->trampoline
;
615 if (!strcmp (callinfo
->name
, "mono_thread_interruption_checkpoint"))
616 /* This icall is used to check for exceptions, so don't check in the wrapper */
619 name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
620 wrapper
= mono_marshal_get_icall_wrapper (callinfo
->sig
, name
, callinfo
->func
, check_exc
);
624 trampoline
= mono_compile_method_checked (wrapper
, &error
);
625 mono_error_assert_ok (&error
);
628 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, &error
);
629 mono_error_assert_ok (&error
);
630 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
634 if (!callinfo
->trampoline
) {
635 mono_register_jit_icall_wrapper (callinfo
, trampoline
);
636 callinfo
->trampoline
= trampoline
;
638 mono_loader_unlock ();
640 return callinfo
->trampoline
;
644 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
646 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
649 static MonoJitDynamicMethodInfo
*
650 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
652 MonoJitDynamicMethodInfo
*res
;
654 if (domain_jit_info (domain
)->dynamic_code_hash
)
655 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
662 register_opcode_emulation (int opcode
, const char *name
, const char *sigstr
, gpointer func
, const char *symbol
, gboolean no_throw
)
665 mini_register_opcode_emulation (opcode
, name
, sigstr
, func
, symbol
, no_throw
);
667 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
669 g_assert (!sig
->hasthis
);
670 g_assert (sig
->param_count
< 3);
672 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
673 mono_register_jit_icall_full (func
, name
, sig
, no_throw
, TRUE
, symbol
);
678 * For JIT icalls implemented in C.
679 * NAME should be the same as the name of the C function whose address is FUNC.
680 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
681 * can't throw exceptions.
684 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean avoid_wrapper
)
686 MonoMethodSignature
*sig
;
689 sig
= mono_create_icall_signature (sigstr
);
693 mono_register_jit_icall_full (func
, name
, sig
, avoid_wrapper
, FALSE
, avoid_wrapper
? name
: NULL
);
697 register_icall_no_wrapper (gpointer func
, const char *name
, const char *sigstr
)
699 MonoMethodSignature
*sig
;
702 sig
= mono_create_icall_signature (sigstr
);
706 mono_register_jit_icall_full (func
, name
, sig
, TRUE
, FALSE
, name
);
710 register_icall_with_wrapper (gpointer func
, const char *name
, const char *sigstr
)
712 MonoMethodSignature
*sig
;
715 sig
= mono_create_icall_signature (sigstr
);
719 mono_register_jit_icall_full (func
, name
, sig
, FALSE
, FALSE
, NULL
);
723 register_dyn_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
725 MonoMethodSignature
*sig
;
728 sig
= mono_create_icall_signature (sigstr
);
732 mono_register_jit_icall (func
, name
, sig
, save
);
738 MonoJitTlsData
*jit_tls
;
740 if ((jit_tls
= mono_tls_get_jit_tls ()))
743 * We do not assert here because this function can be called from
744 * mini-gc.c on a thread that has not executed any managed code, yet
745 * (the thread object allocation can trigger a collection).
751 mono_get_lmf_addr (void)
753 return (MonoLMF
**)mono_tls_get_lmf_addr ();
757 mono_set_lmf (MonoLMF
*lmf
)
759 (*mono_get_lmf_addr ()) = lmf
;
763 mono_get_jit_tls (void)
765 return (MonoJitTlsData
*)mono_tls_get_jit_tls ();
769 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
771 MonoThreadInfo
*info
;
773 mono_tls_set_jit_tls (jit_tls
);
775 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
776 info
= mono_thread_info_current ();
778 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
782 mono_set_lmf_addr (gpointer lmf_addr
)
784 MonoThreadInfo
*info
;
786 mono_tls_set_lmf_addr (lmf_addr
);
788 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
789 info
= mono_thread_info_current ();
791 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
795 * mono_jit_thread_attach:
797 * Called by Xamarin.Mac and other products. Attach thread to runtime if
798 * needed and switch to @domain.
800 * @return the original domain which needs to be restored, or NULL.
803 mono_jit_thread_attach (MonoDomain
*domain
)
808 g_assert (!mono_threads_is_coop_enabled ());
811 /* Happens when called from AOTed code which is only used in the root domain. */
812 domain
= mono_get_root_domain ();
817 attached
= mono_tls_get_jit_tls () != NULL
;
820 mono_thread_attach (domain
);
823 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
826 orig
= mono_domain_get ();
828 mono_domain_set (domain
, TRUE
);
830 return orig
!= domain
? orig
: NULL
;
834 * mono_jit_set_domain:
836 * Set domain to @domain if @domain is not null
839 mono_jit_set_domain (MonoDomain
*domain
)
841 g_assert (!mono_threads_is_coop_enabled ());
844 mono_domain_set (domain
, TRUE
);
849 * \param obj exception object
850 * Abort the thread, print exception information and stack trace
853 mono_thread_abort (MonoObject
*obj
)
855 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
857 /* handle_remove should be eventually called for this thread, too
860 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
861 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
)) {
864 mono_invoke_unhandled_exception_hook (obj
);
869 setup_jit_tls_data (gpointer stack_start
, gpointer abort_func
)
871 MonoJitTlsData
*jit_tls
;
874 jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
878 jit_tls
= g_new0 (MonoJitTlsData
, 1);
880 jit_tls
->abort_func
= (void (*)(MonoObject
*))abort_func
;
881 jit_tls
->end_of_stack
= stack_start
;
883 mono_set_jit_tls (jit_tls
);
885 lmf
= g_new0 (MonoLMF
, 1);
886 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
888 jit_tls
->first_lmf
= lmf
;
890 mono_set_lmf_addr (&jit_tls
->lmf
);
894 #ifdef MONO_ARCH_HAVE_TLS_INIT
895 mono_arch_tls_init ();
898 mono_setup_altstack (jit_tls
);
904 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
906 mono_arch_free_jit_tls_data (jit_tls
);
907 mono_free_altstack (jit_tls
);
909 g_free (jit_tls
->first_lmf
);
914 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
916 MonoThreadInfo
*thread
;
917 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
918 thread
= mono_thread_info_current_unchecked ();
920 thread
->jit_data
= jit_tls
;
922 mono_arch_cpu_init ();
925 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
928 mono_thread_abort_dummy (MonoObject
*obj
)
930 if (mono_thread_attach_aborted_cb
)
931 mono_thread_attach_aborted_cb (obj
);
933 mono_thread_abort (obj
);
937 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
939 MonoThreadInfo
*thread
;
940 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
941 thread
= mono_thread_info_current_unchecked ();
943 thread
->jit_data
= jit_tls
;
945 mono_arch_cpu_init ();
949 mini_thread_cleanup (MonoNativeThreadId tid
)
951 MonoJitTlsData
*jit_tls
= NULL
;
952 MonoThreadInfo
*info
;
954 info
= mono_thread_info_current_unchecked ();
956 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
957 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
958 * not a trivial thing.
960 * The current offender is mono_thread_manage which cleanup threads from the outside.
962 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
963 jit_tls
= (MonoJitTlsData
*)info
->jit_data
;
964 info
->jit_data
= NULL
;
966 mono_set_jit_tls (NULL
);
968 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
969 if (mono_get_lmf ()) {
971 mono_set_lmf_addr (NULL
);
974 info
= mono_thread_info_lookup (tid
);
976 jit_tls
= (MonoJitTlsData
*)info
->jit_data
;
977 info
->jit_data
= NULL
;
979 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
983 free_jit_tls_data (jit_tls
);
987 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
989 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
993 ji
->data
.target
= target
;
999 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1001 static const char* const patch_info_str
[] = {
1002 #define PATCH_INFO(a,b) "" #a,
1003 #include "patch-info.h"
1008 mono_ji_type_to_string (MonoJumpInfoType type
)
1010 return patch_info_str
[type
];
1014 mono_print_ji (const MonoJumpInfo
*ji
)
1017 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1018 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1020 printf ("[RGCTX_FETCH ");
1021 mono_print_ji (entry
->data
);
1022 printf (" - %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1025 case MONO_PATCH_INFO_METHODCONST
: {
1026 char *s
= mono_method_full_name (ji
->data
.method
, TRUE
);
1027 printf ("[METHODCONST - %s]", s
);
1031 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
1032 printf ("[INTERNAL_METHOD - %s]", ji
->data
.name
);
1036 printf ("[%s]", patch_info_str
[ji
->type
]);
1044 mono_ji_type_to_string (MonoJumpInfoType type
)
1050 mono_print_ji (const MonoJumpInfo
*ji
)
1057 * mono_patch_info_dup_mp:
1059 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1062 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1064 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1065 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1067 switch (patch_info
->type
) {
1068 case MONO_PATCH_INFO_RVA
:
1069 case MONO_PATCH_INFO_LDSTR
:
1070 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1071 case MONO_PATCH_INFO_LDTOKEN
:
1072 case MONO_PATCH_INFO_DECLSEC
:
1073 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1074 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1076 case MONO_PATCH_INFO_SWITCH
:
1077 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1078 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1079 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1080 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1082 case MONO_PATCH_INFO_RGCTX_FETCH
:
1083 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1084 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1085 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1086 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1088 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1089 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1090 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1092 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1093 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1094 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1096 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1097 MonoGSharedVtMethodInfo
*info
;
1098 MonoGSharedVtMethodInfo
*oinfo
;
1101 oinfo
= patch_info
->data
.gsharedvt_method
;
1102 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1103 res
->data
.gsharedvt_method
= info
;
1104 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1105 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1106 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1107 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1108 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1110 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1112 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1113 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1116 case MONO_PATCH_INFO_VIRT_METHOD
: {
1117 MonoJumpInfoVirtMethod
*info
;
1118 MonoJumpInfoVirtMethod
*oinfo
;
1120 oinfo
= patch_info
->data
.virt_method
;
1121 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1122 res
->data
.virt_method
= info
;
1123 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1134 mono_patch_info_hash (gconstpointer data
)
1136 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1139 case MONO_PATCH_INFO_RVA
:
1140 case MONO_PATCH_INFO_LDSTR
:
1141 case MONO_PATCH_INFO_LDTOKEN
:
1142 case MONO_PATCH_INFO_DECLSEC
:
1143 return (ji
->type
<< 8) | ji
->data
.token
->token
;
1144 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1145 return (ji
->type
<< 8) | ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1146 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1147 return (ji
->type
<< 8) | g_str_hash (ji
->data
.name
);
1148 case MONO_PATCH_INFO_VTABLE
:
1149 case MONO_PATCH_INFO_CLASS
:
1150 case MONO_PATCH_INFO_IID
:
1151 case MONO_PATCH_INFO_ADJUSTED_IID
:
1152 case MONO_PATCH_INFO_METHODCONST
:
1153 case MONO_PATCH_INFO_METHOD
:
1154 case MONO_PATCH_INFO_METHOD_JUMP
:
1155 case MONO_PATCH_INFO_IMAGE
:
1156 case MONO_PATCH_INFO_ICALL_ADDR
:
1157 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1158 case MONO_PATCH_INFO_FIELD
:
1159 case MONO_PATCH_INFO_SFLDA
:
1160 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1161 case MONO_PATCH_INFO_METHOD_RGCTX
:
1162 case MONO_PATCH_INFO_SIGNATURE
:
1163 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1164 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1165 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1166 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1167 return (ji
->type
<< 8) | (gssize
)ji
->data
.target
;
1168 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1169 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt
->method
;
1170 case MONO_PATCH_INFO_RGCTX_FETCH
:
1171 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1172 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1174 return (ji
->type
<< 8) | (gssize
)e
->method
| (e
->in_mrgctx
) | e
->info_type
| mono_patch_info_hash (e
->data
);
1176 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1177 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1178 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1179 case MONO_PATCH_INFO_GC_NURSERY_START
:
1180 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1181 case MONO_PATCH_INFO_GOT_OFFSET
:
1182 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1183 case MONO_PATCH_INFO_AOT_MODULE
:
1184 case MONO_PATCH_INFO_JIT_THREAD_ATTACH
:
1185 return (ji
->type
<< 8);
1186 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1187 return (ji
->type
<< 8) | (ji
->data
.index
);
1188 case MONO_PATCH_INFO_SWITCH
:
1189 return (ji
->type
<< 8) | ji
->data
.table
->table_size
;
1190 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1191 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt_method
->method
;
1192 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1193 /* Hash on the selector name */
1194 return g_str_hash (ji
->data
.target
);
1195 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1196 return (ji
->type
<< 8) | (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1197 case MONO_PATCH_INFO_LDSTR_LIT
:
1198 return g_str_hash (ji
->data
.target
);
1199 case MONO_PATCH_INFO_VIRT_METHOD
: {
1200 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1202 return (ji
->type
<< 8) | (gssize
)info
->klass
| (gssize
)info
->method
;
1204 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1205 return (ji
->type
<< 8) | g_str_hash (ji
->data
.target
);
1206 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1207 return (ji
->type
<< 8) | mono_signature_hash (ji
->data
.sig
);
1209 printf ("info type: %d\n", ji
->type
);
1210 mono_print_ji (ji
); printf ("\n");
1211 g_assert_not_reached ();
1217 * mono_patch_info_equal:
1219 * This might fail to recognize equivalent patches, i.e. floats, so its only
1220 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1224 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1226 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1227 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1229 if (ji1
->type
!= ji2
->type
)
1232 switch (ji1
->type
) {
1233 case MONO_PATCH_INFO_RVA
:
1234 case MONO_PATCH_INFO_LDSTR
:
1235 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1236 case MONO_PATCH_INFO_LDTOKEN
:
1237 case MONO_PATCH_INFO_DECLSEC
:
1238 if ((ji1
->data
.token
->image
!= ji2
->data
.token
->image
) ||
1239 (ji1
->data
.token
->token
!= ji2
->data
.token
->token
) ||
1240 (ji1
->data
.token
->has_context
!= ji2
->data
.token
->has_context
) ||
1241 (ji1
->data
.token
->context
.class_inst
!= ji2
->data
.token
->context
.class_inst
) ||
1242 (ji1
->data
.token
->context
.method_inst
!= ji2
->data
.token
->context
.method_inst
))
1245 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1246 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1247 case MONO_PATCH_INFO_RGCTX_FETCH
:
1248 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1249 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1250 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1252 return e1
->method
== e2
->method
&& e1
->in_mrgctx
== e2
->in_mrgctx
&& e1
->info_type
== e2
->info_type
&& mono_patch_info_equal (e1
->data
, e2
->data
);
1254 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1255 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1256 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1258 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1260 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1261 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1262 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1263 return ji1
->data
.del_tramp
->klass
== ji2
->data
.del_tramp
->klass
&& ji1
->data
.del_tramp
->method
== ji2
->data
.del_tramp
->method
&& ji1
->data
.del_tramp
->is_virtual
== ji2
->data
.del_tramp
->is_virtual
;
1264 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1265 return ji1
->data
.index
== ji2
->data
.index
;
1266 case MONO_PATCH_INFO_VIRT_METHOD
:
1267 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1268 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1269 if (ji1
->data
.target
== ji2
->data
.target
)
1271 return strcmp (ji1
->data
.target
, ji2
->data
.target
) == 0 ? 1 : 0;
1272 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1273 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
) ? 1 : 0;
1275 if (ji1
->data
.target
!= ji2
->data
.target
)
1284 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1286 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1287 gconstpointer target
= NULL
;
1291 switch (patch_info
->type
) {
1292 case MONO_PATCH_INFO_BB
:
1294 * FIXME: This could be hit for methods without a prolog. Should use -1
1295 * but too much code depends on a 0 initial value.
1297 //g_assert (patch_info->data.bb->native_offset);
1298 target
= patch_info
->data
.bb
->native_offset
+ code
;
1300 case MONO_PATCH_INFO_ABS
:
1301 target
= patch_info
->data
.target
;
1303 case MONO_PATCH_INFO_LABEL
:
1304 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1306 case MONO_PATCH_INFO_IP
:
1309 case MONO_PATCH_INFO_METHOD_REL
:
1310 target
= code
+ patch_info
->data
.offset
;
1312 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
1313 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1315 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info
->data
.name
);
1316 g_assert_not_reached ();
1318 target
= mono_icall_get_wrapper (mi
);
1321 case MONO_PATCH_INFO_JIT_ICALL_ADDR
: {
1322 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1324 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info
->data
.name
);
1325 g_assert_not_reached ();
1330 case MONO_PATCH_INFO_METHOD_JUMP
:
1331 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1332 if (!mono_error_ok (error
))
1335 case MONO_PATCH_INFO_METHOD
:
1336 if (patch_info
->data
.method
== method
) {
1339 /* get the trampoline to the method from the domain */
1340 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1341 if (!mono_error_ok (error
))
1345 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1348 mono_domain_lock (domain
);
1349 if (!domain_jit_info (domain
)->method_code_hash
)
1350 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1351 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1353 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1354 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1356 mono_domain_unlock (domain
);
1360 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1361 #if defined(__native_client_codegen__)
1362 target
= (gpointer
)&__nacl_thread_suspension_needed
;
1364 g_assert (mono_threads_is_coop_enabled ());
1365 target
= (gpointer
)&mono_polling_required
;
1368 case MONO_PATCH_INFO_SWITCH
: {
1369 gpointer
*jump_table
;
1371 #if defined(__native_client__) && defined(__native_client_codegen__)
1372 /* This memory will leak, but we don't care if we're */
1373 /* not deleting JIT'd methods anyway */
1374 jump_table
= g_malloc0 (sizeof(gpointer
) * patch_info
->data
.table
->table_size
);
1376 if (method
&& method
->dynamic
) {
1377 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1379 if (mono_aot_only
) {
1380 jump_table
= (void **)mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1382 jump_table
= (void **)mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1387 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1388 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1391 target
= jump_table
;
1394 case MONO_PATCH_INFO_METHODCONST
:
1395 case MONO_PATCH_INFO_CLASS
:
1396 case MONO_PATCH_INFO_IMAGE
:
1397 case MONO_PATCH_INFO_FIELD
:
1398 case MONO_PATCH_INFO_SIGNATURE
:
1399 case MONO_PATCH_INFO_AOT_MODULE
:
1400 target
= patch_info
->data
.target
;
1402 case MONO_PATCH_INFO_IID
:
1403 mono_class_init (patch_info
->data
.klass
);
1404 target
= GUINT_TO_POINTER (patch_info
->data
.klass
->interface_id
);
1406 case MONO_PATCH_INFO_ADJUSTED_IID
:
1407 mono_class_init (patch_info
->data
.klass
);
1408 target
= GUINT_TO_POINTER ((guint32
)(-((patch_info
->data
.klass
->interface_id
+ 1) * SIZEOF_VOID_P
)));
1410 case MONO_PATCH_INFO_VTABLE
:
1411 target
= mono_class_vtable (domain
, patch_info
->data
.klass
);
1414 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1415 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1417 if (del_tramp
->is_virtual
)
1418 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1420 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1423 case MONO_PATCH_INFO_SFLDA
: {
1424 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.field
->parent
);
1426 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1427 gpointer addr
= NULL
;
1429 mono_domain_lock (domain
);
1430 if (domain
->special_static_fields
)
1431 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1432 mono_domain_unlock (domain
);
1438 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (method
&& mono_class_needs_cctor_run (vtable
->klass
, method
)))
1439 /* Done by the generated code */
1443 if (!mono_runtime_class_init_full (vtable
, error
)) {
1448 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1451 case MONO_PATCH_INFO_RVA
: {
1452 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1455 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1456 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1459 case MONO_PATCH_INFO_R4
:
1460 case MONO_PATCH_INFO_R8
:
1461 target
= patch_info
->data
.target
;
1463 case MONO_PATCH_INFO_EXC_NAME
:
1464 target
= patch_info
->data
.name
;
1466 case MONO_PATCH_INFO_LDSTR
:
1468 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1469 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1471 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1473 MonoClass
*handle_class
;
1475 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1476 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1477 if (!mono_error_ok (error
))
1479 mono_class_init (handle_class
);
1480 mono_class_init (mono_class_from_mono_type ((MonoType
*)handle
));
1482 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1483 if (!mono_error_ok (error
))
1487 case MONO_PATCH_INFO_LDTOKEN
: {
1489 MonoClass
*handle_class
;
1491 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1492 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1493 if (!mono_error_ok (error
))
1494 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error
));
1495 mono_class_init (handle_class
);
1500 case MONO_PATCH_INFO_DECLSEC
:
1501 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1503 case MONO_PATCH_INFO_ICALL_ADDR
:
1504 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1505 /* run_cctors == 0 -> AOT */
1506 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1507 const char *exc_class
;
1508 const char *exc_arg
;
1511 target
= mono_lookup_pinvoke_call (patch_info
->data
.method
, &exc_class
, &exc_arg
);
1513 if (mono_aot_only
) {
1514 mono_error_set_exception_instance (error
, mono_exception_from_name_msg (mono_defaults
.corlib
, "System", exc_class
, exc_arg
));
1517 g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1523 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1525 if (!target
&& run_cctors
)
1526 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1529 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1530 target
= mono_thread_interruption_request_flag ();
1532 case MONO_PATCH_INFO_METHOD_RGCTX
: {
1533 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.method
->klass
);
1536 target
= mono_method_lookup_rgctx (vtable
, mini_method_get_context (patch_info
->data
.method
)->method_inst
);
1539 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1540 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1542 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1545 case MONO_PATCH_INFO_BB_OVF
:
1546 case MONO_PATCH_INFO_EXC_OVF
:
1547 case MONO_PATCH_INFO_GOT_OFFSET
:
1548 case MONO_PATCH_INFO_NONE
:
1550 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1551 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1553 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1556 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1557 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1559 /* AOT, not needed */
1562 target
= mono_arch_get_seq_point_info (domain
, code
);
1565 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1566 int card_table_shift_bits
;
1567 gpointer card_table_mask
;
1569 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1572 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1576 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1579 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1583 mono_gc_get_nursery (&shift_bits
, &size
);
1585 target
= (gpointer
)(mgreg_t
)shift_bits
;
1588 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1589 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1592 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1596 case MONO_PATCH_INFO_LDSTR_LIT
: {
1600 len
= strlen ((const char *)patch_info
->data
.target
);
1601 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1602 memcpy (s
, patch_info
->data
.target
, len
);
1607 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1608 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1610 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1611 target
= mono_tls_get_tls_getter (patch_info
->data
.index
, FALSE
);
1613 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1614 target
= mono_tls_get_tls_setter (patch_info
->data
.index
, FALSE
);
1616 case MONO_PATCH_INFO_JIT_THREAD_ATTACH
: {
1617 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1623 g_assert_not_reached ();
1626 return (gpointer
)target
;
1630 mini_init_gsctx (MonoDomain
*domain
, MonoMemPool
*mp
, MonoGenericContext
*context
, MonoGenericSharingContext
*gsctx
)
1632 MonoGenericInst
*inst
;
1635 memset (gsctx
, 0, sizeof (MonoGenericSharingContext
));
1637 if (context
&& context
->class_inst
) {
1638 inst
= context
->class_inst
;
1639 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1640 MonoType
*type
= inst
->type_argv
[i
];
1642 if (mini_is_gsharedvt_gparam (type
))
1643 gsctx
->is_gsharedvt
= TRUE
;
1646 if (context
&& context
->method_inst
) {
1647 inst
= context
->method_inst
;
1649 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1650 MonoType
*type
= inst
->type_argv
[i
];
1652 if (mini_is_gsharedvt_gparam (type
))
1653 gsctx
->is_gsharedvt
= TRUE
;
1659 * LOCKING: Acquires the jit code hash lock.
1662 mini_lookup_method (MonoDomain
*domain
, MonoMethod
*method
, MonoMethod
*shared
)
1665 static gboolean inited
= FALSE
;
1666 static int lookups
= 0;
1667 static int failed_lookups
= 0;
1669 mono_domain_jit_code_hash_lock (domain
);
1670 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
1671 if (!ji
&& shared
) {
1672 /* Try generic sharing */
1673 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, shared
);
1674 if (ji
&& !ji
->has_generic_jit_info
)
1677 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &lookups
);
1678 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &failed_lookups
);
1686 mono_domain_jit_code_hash_unlock (domain
);
1692 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
1697 ji
= mini_lookup_method (domain
, method
, NULL
);
1700 if (!mono_method_is_generic_sharable (method
, FALSE
))
1702 shared
= mini_get_shared_method (method
);
1703 ji
= mini_lookup_method (domain
, method
, shared
);
1710 mono_get_jit_info_from_method (MonoDomain
*domain
, MonoMethod
*method
)
1712 return lookup_method (domain
, method
);
1716 static FILE* perf_map_file
;
1719 mono_enable_jit_map (void)
1721 if (!perf_map_file
) {
1723 g_snprintf (name
, sizeof (name
), "/tmp/perf-%d.map", getpid ());
1725 perf_map_file
= fopen (name
, "w");
1730 mono_emit_jit_tramp (void *start
, int size
, const char *desc
)
1733 fprintf (perf_map_file
, "%llx %x %s\n", (long long unsigned int)(gsize
)start
, size
, desc
);
1737 mono_emit_jit_map (MonoJitInfo
*jinfo
)
1739 if (perf_map_file
) {
1740 char *name
= mono_method_full_name (jinfo_get_method (jinfo
), TRUE
);
1741 mono_emit_jit_tramp (jinfo
->code_start
, jinfo
->code_size
, name
);
1747 mono_jit_map_is_enabled (void)
1749 return perf_map_file
!= NULL
;
1755 no_gsharedvt_in_wrapper (void)
1757 g_assert_not_reached ();
1763 Limit JITing to mono_cpu_count
1764 This ensures there's always room for application progress and not just JITing.
1766 When a JIT request is made, we check if there's an outstanding one for that method and, if it exits, put the thread to sleep.
1767 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1768 Dependency management in this case is too complex to justify implementing it.
1770 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1773 Get rid of cctor invocatio from within the JIT, it increases JIT duration and complicates things A LOT.
1774 Verify that we don't have too many spurious wakeups.
1775 Experiment with limiting to values around mono_cpu_count +/- 1 as this would enable progress during warmup.
1781 } JitCompilationEntry
;
1784 GPtrArray
*in_flight_methods
; //JitCompilationEntry*
1786 int threads_waiting
;
1789 } JitCompilationData
;
1791 static JitCompilationData compilation_data
;
1792 static int jit_methods_waited
, jit_methods_multiple
, jit_methods_overload
, jit_spurious_wakeups
;
1795 mini_jit_init_job_control (void)
1797 mono_coop_mutex_init (&compilation_data
.lock
);
1798 mono_coop_cond_init (&compilation_data
.cond
);
1799 compilation_data
.in_flight_methods
= g_ptr_array_new ();
1803 lock_compilation_data (void)
1805 mono_coop_mutex_lock (&compilation_data
.lock
);
1810 unlock_compilation_data (void)
1813 mono_coop_mutex_unlock (&compilation_data
.lock
);
1816 static JitCompilationEntry
*
1817 find_method (MonoMethod
*method
, MonoDomain
*domain
)
1820 for (i
= 0; i
< compilation_data
.in_flight_methods
->len
; ++i
){
1821 JitCompilationEntry
*e
= compilation_data
.in_flight_methods
->pdata
[i
];
1822 if (e
->method
== method
&& e
->domain
== domain
)
1830 add_current_thread (MonoJitTlsData
*jit_tls
)
1832 if (jit_tls
->active_jit_methods
== 0)
1833 ++compilation_data
.active_threads
;
1834 ++jit_tls
->active_jit_methods
;
1837 //Returns true if this thread should wait
1839 should_wait_for_available_cpu_capacity (void)
1841 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1843 //We can't suspend threads that are already JIT'ing something or we risk deadlocking
1844 if (jit_tls
->active_jit_methods
> 0)
1847 //If there are as many active threads as cores, JITing more will cause thrashing
1848 if (compilation_data
.active_threads
>= mono_cpu_count ()) {
1849 ++jit_methods_overload
;
1856 * Returns true if this method waited successfully for another thread to JIT it
1859 wait_or_register_method_to_compile (MonoMethod
*method
, MonoDomain
*domain
)
1861 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1862 JitCompilationEntry
*entry
;
1865 static gboolean inited
;
1867 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_waited
);
1868 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_multiple
);
1869 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_overload
);
1870 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_spurious_wakeups
);
1874 lock_compilation_data ();
1877 while (should_wait_for_available_cpu_capacity ()) {
1879 ++compilation_data
.threads_waiting
;
1880 mono_coop_cond_wait (&compilation_data
.cond
, &compilation_data
.lock
);
1881 --compilation_data
.threads_waiting
;
1883 ++jit_spurious_wakeups
;
1887 if (!(entry
= find_method (method
, domain
))) {
1888 entry
= g_new (JitCompilationEntry
, 1);
1889 entry
->method
= method
;
1890 entry
->domain
= domain
;
1892 g_ptr_array_add (compilation_data
.in_flight_methods
, entry
);
1893 add_current_thread (jit_tls
);
1894 unlock_compilation_data ();
1896 } else if (jit_tls
->active_jit_methods
> 0) {
1897 //We can't suspend the current thread if it's already JITing a method.
1898 //Dependency management is too compilated and we want to get rid of this anyways.
1900 ++jit_methods_multiple
;
1901 unlock_compilation_data ();
1904 ++jit_methods_waited
;
1907 ++compilation_data
.threads_waiting
;
1908 mono_coop_cond_wait (&compilation_data
.cond
, &compilation_data
.lock
);
1909 --compilation_data
.threads_waiting
;
1911 if (!find_method (method
, domain
)) {
1912 unlock_compilation_data ();
1915 ++jit_spurious_wakeups
;
1922 unregister_method_for_compile (MonoMethod
*method
, MonoDomain
*target_domain
)
1924 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1926 lock_compilation_data ();
1928 --jit_tls
->active_jit_methods
;
1929 if (jit_tls
->active_jit_methods
== 0)
1930 --compilation_data
.active_threads
;
1932 JitCompilationEntry
*entry
= find_method (method
, target_domain
);
1933 g_assert (entry
); // It would be weird to fail
1934 if (--entry
->count
== 0) {
1935 g_ptr_array_remove (compilation_data
.in_flight_methods
, entry
);
1939 if (compilation_data
.threads_waiting
)
1940 mono_coop_cond_broadcast (&compilation_data
.cond
);
1941 unlock_compilation_data ();
1946 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
1948 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
1950 gpointer code
= NULL
, p
;
1952 MonoJitICallInfo
*callinfo
= NULL
;
1953 WrapperInfo
*winfo
= NULL
;
1957 #ifdef ENABLE_INTERPRETER
1958 if (mono_use_interpreter
&& !jit_only
) {
1959 code
= mono_interp_create_method_pointer (method
, error
);
1966 /* Should be handled by the caller */
1967 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
1970 * ICALL wrappers are handled specially, since there is only one copy of them
1971 * shared by all appdomains.
1973 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1974 winfo
= mono_marshal_get_wrapper_info (method
);
1975 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
1976 callinfo
= mono_find_jit_icall_by_addr (winfo
->d
.icall
.func
);
1977 g_assert (callinfo
);
1979 /* Must be domain neutral since there is only one copy */
1980 opt
|= MONO_OPT_SHARED
;
1982 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
1983 opt
&= ~MONO_OPT_SHARED
;
1986 if (opt
& MONO_OPT_SHARED
)
1987 target_domain
= mono_get_root_domain ();
1989 target_domain
= domain
;
1991 if (method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
1992 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
1995 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
1996 MonoGenericContext
*ctx
= NULL
;
1997 if (method
->is_inflated
)
1998 ctx
= mono_method_get_context (method
);
1999 method
= info
->d
.synchronized_inner
.method
;
2001 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2002 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
2008 info
= lookup_method (target_domain
, method
);
2010 /* We can't use a domain specific method in another domain */
2011 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2014 mono_jit_stats
.methods_lookups
++;
2015 vtable
= mono_class_vtable_full (domain
, method
->klass
, error
);
2019 if (!mono_runtime_class_init_full (vtable
, error
))
2021 return mono_create_ftnptr (target_domain
, info
->code_start
);
2025 #ifdef MONO_USE_AOT_COMPILER
2026 if (opt
& MONO_OPT_AOT
) {
2027 MonoDomain
*domain
= mono_domain_get ();
2029 mono_class_init (method
->klass
);
2031 if ((code
= mono_aot_get_method_checked (domain
, method
, error
))) {
2034 if (mono_runtime_is_critical_method (method
) || mono_gc_is_critical_method (method
)) {
2036 * The suspend code needs to be able to lookup these methods by ip in async context,
2037 * so preload their jit info.
2039 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, code
);
2044 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2045 * This is not a problem, since it will be initialized when the method is first
2046 * called by init_method ().
2048 if (!mono_llvm_only
) {
2049 vtable
= mono_class_vtable (domain
, method
->klass
);
2051 if (!mono_runtime_class_init_full (vtable
, error
))
2060 if (!code
&& mono_llvm_only
) {
2061 if (method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2062 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2064 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
) {
2066 * These wrappers are only created for signatures which are in the program, but
2067 * sometimes we load methods too eagerly and have to create them even if they
2068 * will never be called.
2070 return no_gsharedvt_in_wrapper
;
2076 if (wait_or_register_method_to_compile (method
, target_domain
))
2078 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2079 unregister_method_for_compile (method
, target_domain
);
2081 if (!mono_error_ok (error
))
2084 if (!code
&& mono_llvm_only
) {
2085 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2086 g_assert_not_reached ();
2092 if (method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
) {
2096 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2098 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2102 p
= mono_create_ftnptr (target_domain
, code
);
2105 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2106 mono_loader_lock ();
2108 if (!callinfo
->wrapper
) {
2109 callinfo
->wrapper
= p
;
2110 mono_register_jit_icall_wrapper (callinfo
, p
);
2113 mono_loader_unlock ();
2120 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2124 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2129 * mono_jit_compile_method_jit_only:
2131 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2134 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2138 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2142 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2144 invalidated_delegate_trampoline (char *desc
)
2146 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2147 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2153 * mono_jit_free_method:
2155 * Free all memory allocated by the JIT for METHOD.
2158 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2160 MonoJitDynamicMethodInfo
*ji
;
2161 gboolean destroy
= TRUE
;
2162 GHashTableIter iter
;
2163 MonoJumpList
*jlist
;
2165 g_assert (method
->dynamic
);
2167 mono_domain_lock (domain
);
2168 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2169 mono_domain_unlock (domain
);
2174 mono_debug_remove_method (method
, domain
);
2175 mono_lldb_remove_method (domain
, method
, ji
);
2177 mono_domain_lock (domain
);
2178 g_hash_table_remove (domain_jit_info (domain
)->dynamic_code_hash
, method
);
2179 mono_domain_jit_code_hash_lock (domain
);
2180 mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2181 mono_domain_jit_code_hash_unlock (domain
);
2182 g_hash_table_remove (domain_jit_info (domain
)->jump_trampoline_hash
, method
);
2184 /* requires the domain lock - took above */
2185 mono_conc_hashtable_remove (domain_jit_info (domain
)->runtime_invoke_hash
, method
);
2187 /* Remove jump targets in this method */
2188 g_hash_table_iter_init (&iter
, domain_jit_info (domain
)->jump_target_hash
);
2189 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2190 GSList
*tmp
, *remove
;
2193 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2194 guint8
*ip
= (guint8
*)tmp
->data
;
2196 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2197 remove
= g_slist_prepend (remove
, tmp
);
2199 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2200 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2202 g_slist_free (remove
);
2204 mono_domain_unlock (domain
);
2206 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2207 if (debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2209 * Instead of freeing the code, change it to call an error routine
2210 * so people can fix their code.
2212 char *type
= mono_type_full_name (&method
->klass
->byval_arg
);
2213 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2216 mono_arch_invalidate_method (ji
->ji
, invalidated_delegate_trampoline
, type_and_method
);
2222 * This needs to be done before freeing code_mp, since the code address is the
2223 * key in the table, so if we free the code_mp first, another thread can grab the
2224 * same code address and replace our entry in the table.
2226 mono_jit_info_table_remove (domain
, ji
->ji
);
2229 mono_code_manager_destroy (ji
->code_mp
);
2234 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2236 MonoDomain
*target_domain
;
2239 if (default_opt
& MONO_OPT_SHARED
)
2240 target_domain
= mono_get_root_domain ();
2242 target_domain
= domain
;
2244 info
= lookup_method (target_domain
, method
);
2246 /* We can't use a domain specific method in another domain */
2247 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2248 mono_jit_stats
.methods_lookups
++;
2251 return info
->code_start
;
2260 static guint32 bisect_opt
= 0;
2261 static GHashTable
*bisect_methods_hash
= NULL
;
2264 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2267 char method_name
[2048];
2270 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2271 g_assert (bisect_methods_hash
);
2273 file
= fopen (method_list_filename
, "r");
2276 while (fgets (method_name
, sizeof (method_name
), file
)) {
2277 size_t len
= strlen (method_name
);
2279 g_assert (method_name
[len
- 1] == '\n');
2280 method_name
[len
- 1] = 0;
2281 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2283 g_assert (feof (file
));
2286 gboolean mono_do_single_method_regression
= FALSE
;
2287 guint32 mono_single_method_regression_opt
= 0;
2288 MonoMethod
*mono_current_single_method
;
2289 GSList
*mono_single_method_list
;
2290 GHashTable
*mono_single_method_hash
;
2293 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 default_opt
)
2297 if (bisect_methods_hash
) {
2298 char *name
= mono_method_full_name (method
, TRUE
);
2299 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2302 return default_opt
| bisect_opt
;
2304 if (!mono_do_single_method_regression
)
2306 if (!mono_current_single_method
) {
2307 if (!mono_single_method_hash
)
2308 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2309 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2310 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2311 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2315 if (method
== mono_current_single_method
)
2316 return mono_single_method_regression_opt
;
2321 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2323 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
2328 gpointer compiled_method
;
2329 gpointer runtime_invoke
;
2331 MonoDynCallInfo
*dyn_call_info
;
2332 MonoClass
*ret_box_class
;
2333 MonoMethodSignature
*sig
;
2334 gboolean gsharedvt_invoke
;
2335 gpointer
*wrapper_arg
;
2336 } RuntimeInvokeInfo
;
2338 static RuntimeInvokeInfo
*
2339 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, MonoError
*error
)
2342 RuntimeInvokeInfo
*info
;
2344 info
= g_new0 (RuntimeInvokeInfo
, 1);
2345 info
->compiled_method
= compiled_method
;
2346 if (mono_llvm_only
&& method
->string_ctor
)
2347 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
2349 info
->sig
= mono_method_signature (method
);
2351 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
2352 info
->vtable
= mono_class_vtable_full (domain
, method
->klass
, error
);
2353 if (!mono_error_ok (error
))
2355 g_assert (info
->vtable
);
2357 MonoMethodSignature
*sig
= info
->sig
;
2361 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2362 * in full-aot mode, so we use a slower, but more generic wrapper if
2363 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2365 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2366 if (!mono_llvm_only
&& (mono_aot_only
|| debug_options
.dyn_runtime_invoke
)) {
2367 gboolean supported
= TRUE
;
2370 if (method
->string_ctor
)
2371 sig
= mono_marshal_get_string_ctor_signature (method
);
2373 for (i
= 0; i
< sig
->param_count
; ++i
) {
2374 MonoType
*t
= sig
->params
[i
];
2376 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
2380 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
2384 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
2388 ret_type
= sig
->ret
;
2389 switch (ret_type
->type
) {
2390 case MONO_TYPE_VOID
:
2402 case MONO_TYPE_BOOLEAN
:
2403 case MONO_TYPE_CHAR
:
2406 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2409 info
->ret_box_class
= mono_defaults
.int_class
;
2411 case MONO_TYPE_STRING
:
2412 case MONO_TYPE_CLASS
:
2413 case MONO_TYPE_ARRAY
:
2414 case MONO_TYPE_SZARRAY
:
2415 case MONO_TYPE_OBJECT
:
2417 case MONO_TYPE_GENERICINST
:
2418 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
2419 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2421 case MONO_TYPE_VALUETYPE
:
2422 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2425 g_assert_not_reached ();
2429 if (!info
->dyn_call_info
) {
2430 if (mono_llvm_only
) {
2431 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2432 g_assert_not_reached ();
2434 info
->gsharedvt_invoke
= TRUE
;
2435 if (!callee_gsharedvt
) {
2436 /* Invoke a gsharedvt out wrapper instead */
2437 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2438 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2440 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
2441 info
->wrapper_arg
[0] = mini_add_method_wrappers_llvmonly (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
2443 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2444 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2445 g_free (wrapper_sig
);
2447 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
2448 if (!mono_error_ok (error
)) {
2453 /* Gsharedvt methods can be invoked the same way */
2454 /* The out wrapper has the same signature as the compiled gsharedvt method */
2455 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2457 info
->wrapper_arg
= mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
;
2459 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2460 g_free (wrapper_sig
);
2463 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
2464 if (!mono_error_ok (error
)) {
2474 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2476 MonoMethodSignature
*sig
= info
->sig
;
2477 MonoDomain
*domain
= mono_domain_get ();
2478 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2480 gpointer retval_ptr
;
2481 guint8 retval
[256];
2482 gpointer
*param_refs
;
2487 g_assert (info
->gsharedvt_invoke
);
2490 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2491 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2492 * signatures, so we only have to generate runtime invoke wrappers for these
2494 * This code also handles invocation of gsharedvt methods directly, no
2495 * out wrappers are used in that case.
2497 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2498 param_refs
= (gpointer
*)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2501 * The runtime invoke wrappers expects pointers to primitive types, so have to
2505 args
[pindex
++] = &obj
;
2506 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
2507 retval_ptr
= (gpointer
)&retval
;
2508 args
[pindex
++] = &retval_ptr
;
2510 for (i
= 0; i
< sig
->param_count
; ++i
) {
2511 MonoType
*t
= sig
->params
[i
];
2513 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
2514 MonoClass
*klass
= mono_class_from_mono_type (t
);
2515 guint8
*nullable_buf
;
2518 size
= mono_class_value_size (klass
, NULL
);
2519 nullable_buf
= g_alloca (size
);
2520 g_assert (nullable_buf
);
2522 /* The argument pointed to by params [i] is either a boxed vtype or null */
2523 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
2524 params
[i
] = nullable_buf
;
2527 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
2528 param_refs
[i
] = params
[i
];
2529 params
[i
] = &(param_refs
[i
]);
2531 args
[pindex
++] = ¶ms
[i
];
2533 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2534 args
[pindex
++] = &info
->wrapper_arg
;
2536 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2538 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
2542 if (sig
->ret
->type
!= MONO_TYPE_VOID
&& info
->ret_box_class
)
2543 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2545 return *(MonoObject
**)retval
;
2549 * mono_jit_runtime_invoke:
2550 * \param method: the method to invoke
2551 * \param obj: this pointer
2552 * \param params: array of parameter values.
2553 * \param exc: Set to the exception raised in the managed method.
2554 * \param error: error or caught exception object
2555 * If \p exc is NULL, \p error is thrown instead.
2556 * If coop is enabled, \p exc argument is ignored -
2557 * all exceptions are caught and propagated through \p error
2560 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2562 MonoMethod
*invoke
, *callee
;
2563 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2564 MonoDomain
*domain
= mono_domain_get ();
2565 MonoJitDomainInfo
*domain_info
;
2566 RuntimeInvokeInfo
*info
, *info2
;
2567 MonoJitInfo
*ji
= NULL
;
2568 gboolean callee_gsharedvt
= FALSE
;
2570 #ifdef ENABLE_INTERPRETER
2571 if (mono_use_interpreter
)
2572 return mono_interp_runtime_invoke (method
, obj
, params
, exc
, error
);
2577 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
2578 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2582 domain_info
= domain_jit_info (domain
);
2584 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
2587 if (mono_security_core_clr_enabled ()) {
2589 * This might be redundant since mono_class_vtable () already does this,
2590 * but keep it just in case for moonlight.
2592 mono_class_setup_vtable (method
->klass
);
2593 if (mono_class_has_failure (method
->klass
)) {
2594 mono_error_set_for_class_failure (error
, method
->klass
);
2596 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
2601 gpointer compiled_method
;
2604 if (method
->klass
->rank
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2605 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2607 * Array Get/Set/Address methods. The JIT implements them using inline code
2608 * inside the runtime invoke wrappers, so no need to compile them.
2610 if (mono_aot_only
) {
2612 * Call a wrapper, since the runtime invoke wrapper was not generated.
2614 MonoMethod
*wrapper
;
2616 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
2617 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
2625 compiled_method
= mono_jit_compile_method (callee
, error
);
2626 if (!compiled_method
) {
2627 g_assert (!mono_error_ok (error
));
2631 if (mono_llvm_only
) {
2632 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
2633 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2634 if (callee_gsharedvt
)
2635 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji
)));
2638 if (!callee_gsharedvt
)
2639 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
2641 compiled_method
= NULL
;
2644 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, error
);
2645 if (!mono_error_ok (error
))
2648 mono_domain_lock (domain
);
2649 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
2650 mono_domain_unlock (domain
);
2658 * We need this here because mono_marshal_get_runtime_invoke can place
2659 * the helper method in System.Object and not the target class.
2661 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
2663 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
2667 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2668 we always catch the exception and propagate it through the MonoError */
2669 gboolean catchExcInMonoError
=
2670 (exc
== NULL
) && mono_threads_is_coop_enabled ();
2671 MonoObject
*invoke_exc
= NULL
;
2672 if (catchExcInMonoError
)
2675 /* The wrappers expect this to be initialized to NULL */
2679 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2680 if (info
->dyn_call_info
) {
2681 MonoMethodSignature
*sig
= mono_method_signature (method
);
2683 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
;
2686 guint8 retval
[256];
2688 if (!dyn_runtime_invoke
) {
2689 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
2690 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method (invoke
, error
);
2691 if (!mono_error_ok (error
))
2695 /* Convert the arguments to the format expected by start_dyn_call () */
2696 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
2699 args
[pindex
++] = &obj
;
2700 for (i
= 0; i
< sig
->param_count
; ++i
) {
2701 MonoType
*t
= sig
->params
[i
];
2704 args
[pindex
++] = ¶ms
[i
];
2705 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
2706 args
[pindex
++] = ¶ms
[i
];
2708 args
[pindex
++] = params
[i
];
2712 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2714 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
, sizeof (buf
));
2716 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
2717 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
2719 if (catchExcInMonoError
&& *exc
!= NULL
) {
2720 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
2724 if (info
->ret_box_class
)
2725 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2727 return *(MonoObject
**)retval
;
2733 if (mono_llvm_only
) {
2734 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
2738 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2740 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
2742 if (catchExcInMonoError
&& *exc
!= NULL
)
2743 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
2752 typedef gpointer (*IMTTrampFunc
) (gpointer
*arg
, MonoMethod
*imt_method
);
2755 * mini_llvmonly_initial_imt_tramp:
2757 * This function is called the first time a call is made through an IMT trampoline.
2758 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2761 mini_llvmonly_initial_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
2763 IMTTrampInfo
*info
= (IMTTrampInfo
*)arg
;
2768 mono_vtable_build_imt_slot (info
->vtable
, info
->slot
);
2770 imt
= (gpointer
*)info
->vtable
;
2771 imt
-= MONO_IMT_SIZE
;
2773 /* Return what the real IMT trampoline returns */
2774 ftndesc
= imt
[info
->slot
];
2777 if (func
== (IMTTrampFunc
)mini_llvmonly_initial_imt_tramp
)
2778 /* Happens when the imt slot contains only a generic virtual method */
2780 return func ((gpointer
*)ftndesc
[1], imt_method
);
2783 /* This is called indirectly through an imt slot. */
2785 mono_llvmonly_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
2789 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2790 while (arg
[i
] && arg
[i
] != imt_method
)
2797 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2799 mono_llvmonly_imt_tramp_1 (gpointer
*arg
, MonoMethod
*imt_method
)
2801 //g_assert (arg [0] == imt_method);
2806 mono_llvmonly_imt_tramp_2 (gpointer
*arg
, MonoMethod
*imt_method
)
2808 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2809 if (arg
[0] == imt_method
)
2816 mono_llvmonly_imt_tramp_3 (gpointer
*arg
, MonoMethod
*imt_method
)
2818 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2819 if (arg
[0] == imt_method
)
2821 else if (arg
[2] == imt_method
)
2828 * A version of the imt trampoline used for generic virtual/variant iface methods.
2829 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2830 * in the search table. The original JIT code had a 'fallback' trampoline it could
2831 * call, but we can't do that, so we just return NULL, and the compiled code
2835 mono_llvmonly_fallback_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
2839 while (arg
[i
] && arg
[i
] != imt_method
)
2848 mono_llvmonly_get_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
, gpointer fail_tramp
)
2852 int i
, index
, real_count
;
2853 gboolean virtual_generic
= FALSE
;
2856 * Create an array which is passed to the imt trampoline functions.
2857 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2861 for (i
= 0; i
< count
; ++i
) {
2862 MonoIMTCheckItem
*item
= imt_entries
[i
];
2864 if (item
->is_equals
)
2866 if (item
->has_target_code
)
2867 virtual_generic
= TRUE
;
2871 * Initialize all vtable entries reachable from this imt slot, so the compiled
2872 * code doesn't have to check it.
2874 for (i
= 0; i
< count
; ++i
) {
2875 MonoIMTCheckItem
*item
= imt_entries
[i
];
2878 if (!item
->is_equals
|| item
->has_target_code
)
2880 vt_slot
= item
->value
.vtable_slot
;
2881 mono_init_vtable_slot (vtable
, vt_slot
);
2884 /* Save the entries into an array */
2885 buf
= (void **)mono_domain_alloc (domain
, (real_count
+ 1) * 2 * sizeof (gpointer
));
2887 for (i
= 0; i
< count
; ++i
) {
2888 MonoIMTCheckItem
*item
= imt_entries
[i
];
2890 if (!item
->is_equals
)
2893 g_assert (item
->key
);
2894 buf
[(index
* 2)] = item
->key
;
2895 if (item
->has_target_code
)
2896 buf
[(index
* 2) + 1] = item
->value
.target_code
;
2898 buf
[(index
* 2) + 1] = vtable
->vtable
[item
->value
.vtable_slot
];
2901 buf
[(index
* 2)] = NULL
;
2902 buf
[(index
* 2) + 1] = fail_tramp
;
2905 * Return a function descriptor for a C function with 'buf' as its argument.
2906 * It will by called by JITted code.
2908 res
= (void **)mono_domain_alloc (domain
, 2 * sizeof (gpointer
));
2909 switch (real_count
) {
2911 res
[0] = mono_llvmonly_imt_tramp_1
;
2914 res
[0] = mono_llvmonly_imt_tramp_2
;
2917 res
[0] = mono_llvmonly_imt_tramp_3
;
2920 res
[0] = mono_llvmonly_imt_tramp
;
2923 if (virtual_generic
|| fail_tramp
)
2924 res
[0] = mono_llvmonly_fallback_imt_tramp
;
2930 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
2932 MonoException
*exc
= NULL
;
2934 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
2935 MONO_SIG_HANDLER_GET_CONTEXT
;
2937 ji
= mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
2939 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
2941 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2942 if (mono_arch_is_int_overflow (ctx
, info
))
2944 * The spec says this throws ArithmeticException, but MS throws the derived
2945 * OverflowException.
2947 exc
= mono_get_exception_overflow ();
2949 exc
= mono_get_exception_divide_by_zero ();
2951 exc
= mono_get_exception_divide_by_zero ();
2955 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
2958 mono_handle_native_crash ("SIGFPE", ctx
, info
);
2959 if (mono_do_crash_chaining
) {
2960 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
2965 mono_arch_handle_exception (ctx
, exc
);
2968 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
2971 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler
)
2973 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
2974 MONO_SIG_HANDLER_GET_CONTEXT
;
2976 if (mono_runtime_get_no_exec ())
2980 mono_handle_native_crash ("SIGILL", ctx
, info
);
2981 if (mono_do_crash_chaining
) {
2982 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
2986 g_assert_not_reached ();
2989 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
2990 #define HAVE_SIG_INFO
2993 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
2996 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
2997 gpointer fault_addr
= NULL
;
2998 #ifdef HAVE_SIG_INFO
2999 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3003 MONO_SIG_HANDLER_GET_CONTEXT
;
3005 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3006 if (mono_arch_is_single_step_event (info
, ctx
)) {
3007 mono_debugger_agent_single_step_event (ctx
);
3009 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3010 mono_debugger_agent_breakpoint_hit (ctx
);
3015 #if defined(HAVE_SIG_INFO)
3016 #if !defined(HOST_WIN32)
3017 fault_addr
= info
->si_addr
;
3018 if (mono_aot_is_pagefault (info
->si_addr
)) {
3019 mono_aot_handle_pagefault (info
->si_addr
);
3024 /* The thread might no be registered with the runtime */
3025 if (!mono_domain_get () || !jit_tls
) {
3026 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3028 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3029 if (mono_do_crash_chaining
) {
3030 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3036 ji
= mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3038 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3039 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3042 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3043 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3044 fault_addr
= info
->si_addr
;
3045 if (fault_addr
== NULL
) {
3048 mono_sigctx_to_monoctx (ctx
, &mctx
);
3050 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3054 if (jit_tls
->stack_size
&&
3055 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3057 * The hard-guard page has been hit: there is not much we can do anymore
3058 * Print a hopefully clear message and abort.
3060 mono_handle_hard_stack_ovf (jit_tls
, ji
, ctx
, (guint8
*)info
->si_addr
);
3061 g_assert_not_reached ();
3063 /* The original handler might not like that it is executed on an altstack... */
3064 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3067 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3072 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3075 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3077 if (mono_do_crash_chaining
) {
3078 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3083 mono_arch_handle_exception (ctx
, NULL
);
3087 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3090 MONO_SIG_HANDLER_GET_CONTEXT
;
3092 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3094 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3096 mono_arch_handle_exception (ctx
, exc
);
3098 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3101 #ifndef DISABLE_REMOTING
3102 /* mono_jit_create_remoting_trampoline:
3103 * @method: pointer to the method info
3105 * Creates a trampoline which calls the remoting functions. This
3106 * is used in the vtable of transparent proxies.
3108 * Returns: a pointer to the newly created code
3111 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3114 guint8
*addr
= NULL
;
3118 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature (method
)->generic_param_count
) {
3119 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3123 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3124 (mono_method_signature (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3125 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
);
3128 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3129 return_val_if_nok (error
, NULL
);
3130 return mono_get_addr_from_ftnptr (addr
);
3134 static G_GNUC_UNUSED
void
3135 no_imt_trampoline (void)
3137 g_assert_not_reached ();
3140 static G_GNUC_UNUSED
void
3141 no_vcall_trampoline (void)
3143 g_assert_not_reached ();
3146 static gpointer
*vtable_trampolines
;
3147 static int vtable_trampolines_size
;
3150 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3152 int index
= slot_index
+ MONO_IMT_SIZE
;
3154 if (mono_llvm_only
) {
3155 if (slot_index
< 0) {
3156 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3157 // FIXME: Memory management
3158 gpointer
*ftndesc
= g_malloc (2 * sizeof (gpointer
));
3159 IMTTrampInfo
*info
= g_new0 (IMTTrampInfo
, 1);
3162 ftndesc
[0] = mini_llvmonly_initial_imt_tramp
;
3164 mono_memory_barrier ();
3171 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3172 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3174 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3178 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3179 while (new_size
<= index
)
3181 new_table
= g_new0 (gpointer
, new_size
);
3183 if (vtable_trampolines
)
3184 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3185 g_free (vtable_trampolines
);
3186 mono_memory_barrier ();
3187 vtable_trampolines
= (void **)new_table
;
3188 vtable_trampolines_size
= new_size
;
3193 if (!vtable_trampolines
[index
])
3194 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3195 return vtable_trampolines
[index
];
3199 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3201 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3205 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3210 gpointer
*imt
= (gpointer
*)vt
;
3211 imt
-= MONO_IMT_SIZE
;
3213 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3217 is_callee_gsharedvt_variable (gpointer addr
)
3220 gboolean callee_gsharedvt
;
3222 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
3224 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3225 if (callee_gsharedvt
)
3226 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji
)));
3227 return callee_gsharedvt
;
3231 mini_get_delegate_arg (MonoMethod
*method
, gpointer method_ptr
)
3233 gpointer arg
= NULL
;
3235 if (mono_method_needs_static_rgctx_invoke (method
, FALSE
))
3236 arg
= mini_method_get_rgctx (method
);
3239 * Avoid adding gsharedvt in wrappers since they might not exist if
3240 * this delegate is called through a gsharedvt delegate invoke wrapper.
3241 * Instead, encode that the method is gsharedvt in del->extra_arg,
3242 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3244 if (method
->is_inflated
&& is_callee_gsharedvt_variable (method_ptr
)) {
3245 g_assert ((((mgreg_t
)arg
) & 1) == 0);
3246 arg
= (gpointer
)(((mgreg_t
)arg
) | 1);
3252 mini_init_delegate (MonoDelegate
*del
)
3255 del
->extra_arg
= mini_get_delegate_arg (del
->method
, del
->method_ptr
);
3256 #ifdef ENABLE_INTERPRETER
3257 if (mono_use_interpreter
)
3258 mono_interp_init_delegate (del
);
3263 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3267 abs_offset
= offset
;
3269 abs_offset
= - abs_offset
;
3270 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ SIZEOF_VOID_P
);
3274 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3276 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3279 static guint8
**cache
= NULL
;
3280 static int cache_size
= 0;
3285 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3288 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3289 is_interface
= mono_class_is_interface (method
->klass
);
3290 load_imt_reg
= is_virtual_generic
|| is_interface
;
3293 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * SIZEOF_VOID_P
;
3295 offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (SIZEOF_VOID_P
));
3297 idx
= (offset
/ SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3298 g_assert (idx
>= 0);
3300 /* Resize the cache to idx + 1 */
3301 if (cache_size
< idx
+ 1) {
3303 if (cache_size
< idx
+ 1) {
3305 int new_cache_size
= idx
+ 1;
3307 new_cache
= g_new0 (guint8
*, new_cache_size
);
3309 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3312 mono_memory_barrier ();
3314 cache_size
= new_cache_size
;
3322 /* FIXME Support more cases */
3323 if (mono_aot_only
) {
3324 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3325 g_assert (cache
[idx
]);
3327 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3333 * mini_parse_debug_option:
3334 * @option: The option to parse.
3336 * Parses debug options for the mono runtime. The options are the same as for
3337 * the MONO_DEBUG environment variable.
3341 mini_parse_debug_option (const char *option
)
3343 if (!strcmp (option
, "handle-sigint"))
3344 debug_options
.handle_sigint
= TRUE
;
3345 else if (!strcmp (option
, "keep-delegates"))
3346 debug_options
.keep_delegates
= TRUE
;
3347 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3348 debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3349 else if (!strcmp (option
, "collect-pagefault-stats"))
3350 debug_options
.collect_pagefault_stats
= TRUE
;
3351 else if (!strcmp (option
, "break-on-unverified"))
3352 debug_options
.break_on_unverified
= TRUE
;
3353 else if (!strcmp (option
, "no-gdb-backtrace"))
3354 debug_options
.no_gdb_backtrace
= TRUE
;
3355 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
3356 debug_options
.suspend_on_native_crash
= TRUE
;
3357 else if (!strcmp (option
, "suspend-on-exception"))
3358 debug_options
.suspend_on_exception
= TRUE
;
3359 else if (!strcmp (option
, "suspend-on-unhandled"))
3360 debug_options
.suspend_on_unhandled
= TRUE
;
3361 else if (!strcmp (option
, "dont-free-domains"))
3362 mono_dont_free_domains
= TRUE
;
3363 else if (!strcmp (option
, "dyn-runtime-invoke"))
3364 debug_options
.dyn_runtime_invoke
= TRUE
;
3365 else if (!strcmp (option
, "gdb"))
3366 debug_options
.gdb
= TRUE
;
3367 else if (!strcmp (option
, "lldb"))
3368 debug_options
.lldb
= TRUE
;
3369 else if (!strcmp (option
, "explicit-null-checks"))
3370 debug_options
.explicit_null_checks
= TRUE
;
3371 else if (!strcmp (option
, "gen-seq-points"))
3372 debug_options
.gen_sdb_seq_points
= TRUE
;
3373 else if (!strcmp (option
, "gen-compact-seq-points"))
3374 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3375 else if (!strcmp (option
, "no-compact-seq-points"))
3376 debug_options
.no_seq_points_compact_data
= TRUE
;
3377 else if (!strcmp (option
, "single-imm-size"))
3378 debug_options
.single_imm_size
= TRUE
;
3379 else if (!strcmp (option
, "init-stacks"))
3380 debug_options
.init_stacks
= TRUE
;
3381 else if (!strcmp (option
, "casts"))
3382 debug_options
.better_cast_details
= TRUE
;
3383 else if (!strcmp (option
, "soft-breakpoints"))
3384 debug_options
.soft_breakpoints
= TRUE
;
3385 else if (!strcmp (option
, "check-pinvoke-callconv"))
3386 debug_options
.check_pinvoke_callconv
= TRUE
;
3387 else if (!strcmp (option
, "use-fallback-tls"))
3388 debug_options
.use_fallback_tls
= TRUE
;
3389 else if (!strcmp (option
, "debug-domain-unload"))
3390 mono_enable_debug_domain_unload (TRUE
);
3391 else if (!strcmp (option
, "partial-sharing"))
3392 mono_set_partial_sharing_supported (TRUE
);
3393 else if (!strcmp (option
, "align-small-structs"))
3394 mono_align_small_structs
= TRUE
;
3395 else if (!strcmp (option
, "native-debugger-break"))
3396 debug_options
.native_debugger_break
= TRUE
;
3397 else if (!strcmp (option
, "disable_omit_fp"))
3398 debug_options
.disable_omit_fp
= TRUE
;
3406 mini_parse_debug_options (void)
3408 char *options
= g_getenv ("MONO_DEBUG");
3409 gchar
**args
, **ptr
;
3414 args
= g_strsplit (options
, ",", -1);
3417 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
3418 const char *arg
= *ptr
;
3420 if (!mini_parse_debug_option (arg
)) {
3421 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
3422 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");
3431 mini_get_debug_options (void)
3433 return &debug_options
;
3437 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
3439 #if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3442 gpointer
* desc
= NULL
;
3444 if ((desc
= g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
3447 desc
= mono_domain_code_reserve (domain
, 2 * sizeof (gpointer
));
3451 # elif defined(__ppc64__) || defined(__powerpc64__)
3453 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
3459 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
3465 mini_get_addr_from_ftnptr (gpointer descr
)
3467 #if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3468 return *(gpointer
*)descr
;
3475 register_jit_stats (void)
3477 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
3478 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
3479 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
3480 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
3481 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_method_to_ir
);
3482 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses
);
3483 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
);
3484 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_long_opts
);
3485 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_typechecks
);
3486 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop
);
3487 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_emulate_ops
);
3488 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches
);
3489 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs
);
3490 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce
);
3491 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_alias_analysis
);
3492 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_if_conversion
);
3493 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_bb_ordering
);
3494 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compile_dominator_info
);
3495 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compute_natural_loops
);
3496 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_insert_safepoints
);
3497 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_compute
);
3498 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_cprop
);
3499 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_deadce
);
3500 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_perform_abc_removal
);
3501 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_remove
);
3502 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop2
);
3503 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs2
);
3504 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce2
);
3505 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches2
);
3506 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_vtype_opts
);
3507 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_array_access_opts
);
3508 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses2
);
3509 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_analyze_liveness
);
3510 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_linear_scan
);
3511 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_arch_allocate_vars
);
3512 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_spill_global_vars
);
3513 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop3
);
3514 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce3
);
3515 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_codegen
);
3516 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_create_jit_info
);
3517 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_gc_create_gc_map
);
3518 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_save_seq_point_info
);
3519 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_time
);
3520 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.basic_blocks
);
3521 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.max_basic_blocks
);
3522 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocate_var
);
3523 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.code_reallocs
);
3524 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_code_size
);
3525 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_seq_points_size
);
3526 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlineable_methods
);
3527 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlined_methods
);
3528 mono_counters_register ("Regvars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.regvars
);
3529 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.locals_stack_size
);
3530 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_lookups
);
3531 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.cil_code_size
);
3532 mono_counters_register ("Native code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.native_code_size
);
3533 mono_counters_register ("Aliases found", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_found
);
3534 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_removed
);
3535 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.loads_eliminated
);
3536 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.stores_eliminated
);
3537 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.optimized_divisions
);
3540 static void runtime_invoke_info_free (gpointer value
);
3543 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
3545 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
3546 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
3548 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
3552 class_method_pair_hash (gconstpointer data
)
3554 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
3556 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
3560 mini_create_jit_domain_info (MonoDomain
*domain
)
3562 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
3564 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3565 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3566 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
3567 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3568 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
3569 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
3570 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3571 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
3572 mono_jit_code_hash_init (&info
->interp_code_hash
);
3574 domain
->runtime_info
= info
;
3578 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
3580 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
3581 g_slist_free (jlist
->list
);
3585 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
3587 GSList
*list
= (GSList
*)value
;
3588 g_slist_free (list
);
3592 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
3594 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
3595 mono_code_manager_destroy (di
->code_mp
);
3600 runtime_invoke_info_free (gpointer value
)
3602 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
3604 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3605 if (info
->dyn_call_info
)
3606 mono_arch_dyn_call_free (info
->dyn_call_info
);
3612 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
3614 g_slist_free (value
);
3618 mini_free_jit_domain_info (MonoDomain
*domain
)
3620 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3622 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
3623 g_hash_table_destroy (info
->jump_target_hash
);
3624 if (info
->jump_target_got_slot_hash
) {
3625 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
3626 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
3628 if (info
->dynamic_code_hash
) {
3629 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
3630 g_hash_table_destroy (info
->dynamic_code_hash
);
3632 if (info
->method_code_hash
)
3633 g_hash_table_destroy (info
->method_code_hash
);
3634 g_hash_table_destroy (info
->jump_trampoline_hash
);
3635 g_hash_table_destroy (info
->jit_trampoline_hash
);
3636 g_hash_table_destroy (info
->delegate_trampoline_hash
);
3637 if (info
->static_rgctx_trampoline_hash
)
3638 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
3639 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
3640 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
3641 g_hash_table_destroy (info
->seq_points
);
3642 g_hash_table_destroy (info
->arch_seq_points
);
3643 if (info
->agent_info
)
3644 mono_debugger_agent_free_domain_info (domain
);
3645 if (info
->gsharedvt_arg_tramp_hash
)
3646 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
3647 if (info
->llvm_jit_callees
) {
3648 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
3649 g_hash_table_destroy (info
->llvm_jit_callees
);
3652 mono_llvm_free_domain_info (domain
);
3655 g_free (domain
->runtime_info
);
3656 domain
->runtime_info
= NULL
;
3659 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3662 code_manager_chunk_new (void *chunk
, int size
)
3664 mono_arch_code_chunk_new (chunk
, size
);
3668 code_manager_chunk_destroy (void *chunk
)
3670 mono_arch_code_chunk_destroy (chunk
);
3677 llvm_init_inner (void)
3679 if (!mono_llvm_load (NULL
))
3690 * Load and initialize LLVM support.
3691 * Return TRUE on success.
3694 mini_llvm_init (void)
3697 static gboolean llvm_inited
;
3698 static gboolean init_result
;
3700 mono_loader_lock_if_inited ();
3702 init_result
= llvm_init_inner ();
3705 mono_loader_unlock_if_inited ();
3713 mini_profiler_enable_with_options (const char* profile_options
)
3715 mini_enable_profiler
= TRUE
;
3716 mini_profiler_options
= g_strdup (profile_options
);
3720 mini_init (const char *filename
, const char *runtime_version
)
3724 MonoRuntimeCallbacks callbacks
;
3725 MonoThreadInfoRuntimeCallbacks ticallbacks
;
3726 MonoCodeManagerCallbacks code_manager_callbacks
;
3728 MONO_VES_INIT_BEGIN ();
3730 CHECKED_MONO_INIT ();
3732 #if defined(__linux__) && !defined(__native_client__)
3733 if (access ("/proc/self/maps", F_OK
) != 0) {
3734 g_print ("Mono requires /proc to be mounted.\n");
3739 mono_os_mutex_init_recursive (&jit_mutex
);
3741 mono_cross_helpers_run ();
3743 mono_counters_init ();
3747 mini_jit_init_job_control ();
3749 /* Happens when using the embedding interface */
3750 if (!default_opt_set
)
3751 default_opt
= mono_parse_default_optimizations (NULL
);
3753 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3755 mono_set_generic_sharing_vt_supported (TRUE
);
3758 mono_set_generic_sharing_vt_supported (TRUE
);
3761 mono_tls_init_runtime_keys ();
3763 if (!global_codeman
)
3764 global_codeman
= mono_code_manager_new ();
3766 memset (&callbacks
, 0, sizeof (callbacks
));
3767 callbacks
.create_ftnptr
= mini_create_ftnptr
;
3768 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
3769 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
3770 callbacks
.set_cast_details
= mono_set_cast_details
;
3771 callbacks
.debug_log
= mono_debugger_agent_debug_log
;
3772 callbacks
.debug_log_is_enabled
= mono_debugger_agent_debug_log_is_enabled
;
3773 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
3774 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
3775 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
3776 callbacks
.init_delegate
= mini_init_delegate
;
3777 #define JIT_INVOKE_WORKS
3778 #ifdef JIT_INVOKE_WORKS
3779 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
3781 #define JIT_TRAMPOLINES_WORK
3782 #ifdef JIT_TRAMPOLINES_WORK
3783 callbacks
.compile_method
= mono_jit_compile_method
;
3784 callbacks
.create_jump_trampoline
= mono_create_jump_trampoline
;
3785 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
3786 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
3787 callbacks
.free_method
= mono_jit_free_method
;
3788 #ifndef DISABLE_REMOTING
3789 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
3793 mono_install_callbacks (&callbacks
);
3795 memset (&ticallbacks
, 0, sizeof (ticallbacks
));
3796 ticallbacks
.setup_async_callback
= mono_setup_async_callback
;
3797 ticallbacks
.thread_state_init_from_sigctx
= mono_thread_state_init_from_sigctx
;
3798 ticallbacks
.thread_state_init_from_handle
= mono_thread_state_init_from_handle
;
3799 ticallbacks
.thread_state_init
= mono_thread_state_init
;
3802 mono_w32handle_init ();
3805 mono_threads_runtime_init (&ticallbacks
);
3807 if (g_hasenv ("MONO_DEBUG")) {
3808 mini_parse_debug_options ();
3811 mono_code_manager_init ();
3813 memset (&code_manager_callbacks
, 0, sizeof (code_manager_callbacks
));
3814 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3815 code_manager_callbacks
.chunk_new
= code_manager_chunk_new
;
3816 code_manager_callbacks
.chunk_destroy
= code_manager_chunk_destroy
;
3818 mono_code_manager_install_callbacks (&code_manager_callbacks
);
3822 mono_arch_cpu_init ();
3826 mono_unwind_init ();
3828 if (mini_get_debug_options ()->lldb
|| g_hasenv ("MONO_LLDB")) {
3829 mono_lldb_init ("");
3830 mono_dont_free_domains
= TRUE
;
3833 #ifdef XDEBUG_ENABLED
3834 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
3836 mono_xdebug_init (mono_xdebug
);
3837 g_free (mono_xdebug
);
3838 /* So methods for multiple domains don't have the same address */
3839 mono_dont_free_domains
= TRUE
;
3840 mono_using_xdebug
= TRUE
;
3841 } else if (mini_get_debug_options ()->gdb
) {
3842 mono_xdebug_init ((char*)"gdb");
3843 mono_dont_free_domains
= TRUE
;
3844 mono_using_xdebug
= TRUE
;
3849 if (mono_use_llvm
) {
3850 if (!mono_llvm_load (NULL
)) {
3851 mono_use_llvm
= FALSE
;
3852 fprintf (stderr
, "Mono Warning: llvm support could not be loaded.\n");
3859 mono_trampolines_init ();
3861 if (default_opt
& MONO_OPT_AOT
)
3864 mono_debugger_agent_init ();
3866 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3867 mono_set_generic_sharing_supported (TRUE
);
3870 mono_threads_signals_init ();
3872 #ifndef MONO_CROSS_COMPILE
3873 mono_runtime_install_handlers ();
3875 mono_threads_install_cleanup (mini_thread_cleanup
);
3877 #ifdef JIT_TRAMPOLINES_WORK
3878 mono_install_create_domain_hook (mini_create_jit_domain_info
);
3879 mono_install_free_domain_hook (mini_free_jit_domain_info
);
3881 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
3882 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
3883 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
3885 if (mini_profiler_enabled ()) {
3886 mono_profiler_load (mini_profiler_get_options ());
3887 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3890 if (debug_options
.collect_pagefault_stats
)
3891 mono_aot_set_make_unreadable (TRUE
);
3893 if (runtime_version
)
3894 domain
= mono_init_version (filename
, runtime_version
);
3896 domain
= mono_init_from_assembly (filename
, filename
);
3898 if (mono_aot_only
) {
3899 /* This helps catch code allocation requests */
3900 mono_code_manager_set_read_only (domain
->code_mp
);
3901 mono_marshal_use_aot_wrappers (TRUE
);
3904 if (mono_llvm_only
) {
3905 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline
);
3906 mono_set_always_build_imt_trampolines (TRUE
);
3907 } else if (mono_aot_only
) {
3908 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
3910 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
3913 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3914 mono_arch_finish_init ();
3918 /* This must come after mono_init () in the aot-only case */
3919 mono_exceptions_init ();
3921 /* This should come after mono_init () too */
3925 mono_create_helper_signatures ();
3928 register_jit_stats ();
3930 #define JIT_CALLS_WORK
3931 #ifdef JIT_CALLS_WORK
3932 /* Needs to be called here since register_jit_icall depends on it */
3933 mono_marshal_init ();
3935 mono_arch_register_lowlevel_calls ();
3939 mono_generic_sharing_init ();
3942 #ifdef MONO_ARCH_SIMD_INTRINSICS
3943 mono_simd_intrinsics_init ();
3946 mono_tasklets_init ();
3948 register_trampolines (domain
);
3950 if (mono_compile_aot
)
3952 * Avoid running managed code when AOT compiling, since the platform
3953 * might only support aot-only execution.
3955 mono_runtime_set_no_exec (TRUE
);
3957 mono_mem_account_register_counters ();
3959 #define JIT_RUNTIME_WORKS
3960 #ifdef JIT_RUNTIME_WORKS
3961 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
3962 mono_runtime_init_checked (domain
, mono_thread_start_cb
, mono_thread_attach_cb
, &error
);
3963 mono_error_assert_ok (&error
);
3964 mono_thread_attach (domain
);
3967 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL
)
3968 mono_runtime_setup_stat_profiler ();
3970 mono_profiler_runtime_initialized ();
3972 MONO_VES_INIT_END ();
3978 register_icalls (void)
3980 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
3981 ves_icall_get_frame_info
);
3982 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
3983 ves_icall_get_trace
);
3984 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
3985 mono_runtime_install_handlers
);
3986 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
3987 mono_runtime_cleanup_handlers
);
3989 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
3990 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
3991 mono_debugger_agent_unhandled_exception
);
3995 * It's important that we pass `TRUE` as the last argument here, as
3996 * it causes the JIT to omit a wrapper for these icalls. If the JIT
3997 * *did* emit a wrapper, we'd be looking at infinite recursion since
3998 * the wrapper would call the icall which would call the wrapper and
4001 register_icall (mono_profiler_method_enter
, "mono_profiler_method_enter", "void ptr", TRUE
);
4002 register_icall (mono_profiler_method_leave
, "mono_profiler_method_leave", "void ptr", TRUE
);
4004 register_icall (mono_trace_enter_method
, "mono_trace_enter_method", NULL
, TRUE
);
4005 register_icall (mono_trace_leave_method
, "mono_trace_leave_method", NULL
, TRUE
);
4006 register_icall (mono_get_lmf_addr
, "mono_get_lmf_addr", "ptr", TRUE
);
4007 register_icall (mono_jit_thread_attach
, "mono_jit_thread_attach", "ptr ptr", TRUE
);
4008 register_icall (mono_jit_set_domain
, "mono_jit_set_domain", "void ptr", TRUE
);
4009 register_icall (mono_domain_get
, "mono_domain_get", "ptr", TRUE
);
4011 register_icall (mono_llvm_throw_exception
, "mono_llvm_throw_exception", "void object", TRUE
);
4012 register_icall (mono_llvm_rethrow_exception
, "mono_llvm_rethrow_exception", "void object", TRUE
);
4013 register_icall (mono_llvm_resume_exception
, "mono_llvm_resume_exception", "void", TRUE
);
4014 register_icall (mono_llvm_match_exception
, "mono_llvm_match_exception", "int ptr int int", TRUE
);
4015 register_icall (mono_llvm_clear_exception
, "mono_llvm_clear_exception", NULL
, TRUE
);
4016 register_icall (mono_llvm_load_exception
, "mono_llvm_load_exception", "object", TRUE
);
4017 register_icall (mono_llvm_throw_corlib_exception
, "mono_llvm_throw_corlib_exception", "void int", TRUE
);
4018 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4019 register_icall (mono_llvm_set_unhandled_exception_handler
, "mono_llvm_set_unhandled_exception_handler", NULL
, TRUE
);
4021 // FIXME: This is broken
4022 register_icall (mono_debug_personality
, "mono_debug_personality", "int int int ptr ptr ptr", TRUE
);
4025 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE
);
4026 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE
);
4027 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE
);
4028 register_icall (mono_thread_get_undeniable_exception
, "mono_thread_get_undeniable_exception", "object", FALSE
);
4029 register_icall (mono_thread_interruption_checkpoint
, "mono_thread_interruption_checkpoint", "object", FALSE
);
4030 register_icall (mono_thread_force_interruption_checkpoint_noraise
, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE
);
4032 #if defined(__native_client__) || defined(__native_client_codegen__)
4033 register_icall (mono_nacl_gc
, "mono_nacl_gc", "void", FALSE
);
4036 if (mono_threads_is_coop_enabled ())
4037 register_icall (mono_threads_state_poll
, "mono_threads_state_poll", "void", FALSE
);
4039 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4040 register_opcode_emulation (OP_LMUL
, "__emul_lmul", "long long long", mono_llmult
, "mono_llmult", FALSE
);
4041 register_opcode_emulation (OP_LDIV
, "__emul_ldiv", "long long long", mono_lldiv
, "mono_lldiv", FALSE
);
4042 register_opcode_emulation (OP_LDIV_UN
, "__emul_ldiv_un", "long long long", mono_lldiv_un
, "mono_lldiv_un", FALSE
);
4043 register_opcode_emulation (OP_LREM
, "__emul_lrem", "long long long", mono_llrem
, "mono_llrem", FALSE
);
4044 register_opcode_emulation (OP_LREM_UN
, "__emul_lrem_un", "long long long", mono_llrem_un
, "mono_llrem_un", FALSE
);
4046 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4047 register_opcode_emulation (OP_LMUL_OVF_UN
, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un
, "mono_llmult_ovf_un", FALSE
);
4048 register_opcode_emulation (OP_LMUL_OVF
, "__emul_lmul_ovf", "long long long", mono_llmult_ovf
, "mono_llmult_ovf", FALSE
);
4051 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4052 register_opcode_emulation (OP_LSHL
, "__emul_lshl", "long long int32", mono_lshl
, "mono_lshl", TRUE
);
4053 register_opcode_emulation (OP_LSHR
, "__emul_lshr", "long long int32", mono_lshr
, "mono_lshr", TRUE
);
4054 register_opcode_emulation (OP_LSHR_UN
, "__emul_lshr_un", "long long int32", mono_lshr_un
, "mono_lshr_un", TRUE
);
4057 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4058 register_opcode_emulation (OP_IDIV
, "__emul_op_idiv", "int32 int32 int32", mono_idiv
, "mono_idiv", FALSE
);
4059 register_opcode_emulation (OP_IDIV_UN
, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un
, "mono_idiv_un", FALSE
);
4060 register_opcode_emulation (OP_IREM
, "__emul_op_irem", "int32 int32 int32", mono_irem
, "mono_irem", FALSE
);
4061 register_opcode_emulation (OP_IREM_UN
, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un
, "mono_irem_un", FALSE
);
4064 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4065 register_opcode_emulation (OP_IMUL
, "__emul_op_imul", "int32 int32 int32", mono_imul
, "mono_imul", TRUE
);
4068 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4069 register_opcode_emulation (OP_IMUL_OVF
, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf
, "mono_imul_ovf", FALSE
);
4070 register_opcode_emulation (OP_IMUL_OVF_UN
, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un
, "mono_imul_ovf_un", FALSE
);
4073 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4074 register_opcode_emulation (OP_FDIV
, "__emul_fdiv", "double double double", mono_fdiv
, "mono_fdiv", FALSE
);
4077 register_opcode_emulation (OP_FCONV_TO_U8
, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8
, "mono_fconv_u8", FALSE
);
4078 register_opcode_emulation (OP_RCONV_TO_U8
, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8
, "mono_rconv_u8", FALSE
);
4079 register_opcode_emulation (OP_FCONV_TO_U4
, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4
, "mono_fconv_u4", FALSE
);
4080 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8
, "mono_fconv_ovf_i8", FALSE
);
4081 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8
, "mono_fconv_ovf_u8", FALSE
);
4082 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8
, "mono_rconv_ovf_i8", FALSE
);
4083 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8
, "mono_rconv_ovf_u8", FALSE
);
4086 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4087 register_opcode_emulation (OP_FCONV_TO_I8
, "__emul_fconv_to_i8", "long double", mono_fconv_i8
, "mono_fconv_i8", FALSE
);
4088 register_opcode_emulation (OP_RCONV_TO_I8
, "__emul_rconv_to_i8", "long float", mono_rconv_i8
, "mono_rconv_i8", FALSE
);
4091 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4092 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
);
4094 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4095 register_opcode_emulation (OP_LCONV_TO_R8
, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8
, "mono_lconv_to_r8", FALSE
);
4097 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4098 register_opcode_emulation (OP_LCONV_TO_R4
, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4
, "mono_lconv_to_r4", FALSE
);
4100 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4101 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
);
4103 #ifdef MONO_ARCH_EMULATE_FREM
4104 #if !defined(__native_client__)
4105 register_opcode_emulation (OP_FREM
, "__emul_frem", "double double double", fmod
, "fmod", FALSE
);
4106 register_opcode_emulation (OP_RREM
, "__emul_rrem", "float float float", fmodf
, "fmodf", FALSE
);
4108 register_opcode_emulation (OP_FREM
, "__emul_frem", "double double double", mono_fmod
, "mono_fmod", FALSE
);
4112 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4113 if (mono_arch_is_soft_float ()) {
4114 register_opcode_emulation (OP_FSUB
, "__emul_fsub", "double double double", mono_fsub
, "mono_fsub", FALSE
);
4115 register_opcode_emulation (OP_FADD
, "__emul_fadd", "double double double", mono_fadd
, "mono_fadd", FALSE
);
4116 register_opcode_emulation (OP_FMUL
, "__emul_fmul", "double double double", mono_fmul
, "mono_fmul", FALSE
);
4117 register_opcode_emulation (OP_FNEG
, "__emul_fneg", "double double", mono_fneg
, "mono_fneg", FALSE
);
4118 register_opcode_emulation (OP_ICONV_TO_R8
, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8
, "mono_conv_to_r8", FALSE
);
4119 register_opcode_emulation (OP_ICONV_TO_R4
, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4
, "mono_conv_to_r4", FALSE
);
4120 register_opcode_emulation (OP_FCONV_TO_R4
, "__emul_fconv_to_r4", "double double", mono_fconv_r4
, "mono_fconv_r4", FALSE
);
4121 register_opcode_emulation (OP_FCONV_TO_I1
, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1
, "mono_fconv_i1", FALSE
);
4122 register_opcode_emulation (OP_FCONV_TO_I2
, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2
, "mono_fconv_i2", FALSE
);
4123 register_opcode_emulation (OP_FCONV_TO_I4
, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4124 register_opcode_emulation (OP_FCONV_TO_U1
, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1
, "mono_fconv_u1", FALSE
);
4125 register_opcode_emulation (OP_FCONV_TO_U2
, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2
, "mono_fconv_u2", FALSE
);
4127 #if SIZEOF_VOID_P == 4
4128 register_opcode_emulation (OP_FCONV_TO_I
, "__emul_fconv_to_i", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4131 register_opcode_emulation (OP_FBEQ
, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq
, "mono_fcmp_eq", FALSE
);
4132 register_opcode_emulation (OP_FBLT
, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt
, "mono_fcmp_lt", FALSE
);
4133 register_opcode_emulation (OP_FBGT
, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt
, "mono_fcmp_gt", FALSE
);
4134 register_opcode_emulation (OP_FBLE
, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le
, "mono_fcmp_le", FALSE
);
4135 register_opcode_emulation (OP_FBGE
, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge
, "mono_fcmp_ge", FALSE
);
4136 register_opcode_emulation (OP_FBNE_UN
, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un
, "mono_fcmp_ne_un", FALSE
);
4137 register_opcode_emulation (OP_FBLT_UN
, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un
, "mono_fcmp_lt_un", FALSE
);
4138 register_opcode_emulation (OP_FBGT_UN
, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un
, "mono_fcmp_gt_un", FALSE
);
4139 register_opcode_emulation (OP_FBLE_UN
, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un
, "mono_fcmp_le_un", FALSE
);
4140 register_opcode_emulation (OP_FBGE_UN
, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un
, "mono_fcmp_ge_un", FALSE
);
4142 register_opcode_emulation (OP_FCEQ
, "__emul_fcmp_ceq", "uint32 double double", mono_fceq
, "mono_fceq", FALSE
);
4143 register_opcode_emulation (OP_FCGT
, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt
, "mono_fcgt", FALSE
);
4144 register_opcode_emulation (OP_FCGT_UN
, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un
, "mono_fcgt_un", FALSE
);
4145 register_opcode_emulation (OP_FCLT
, "__emul_fcmp_clt", "uint32 double double", mono_fclt
, "mono_fclt", FALSE
);
4146 register_opcode_emulation (OP_FCLT_UN
, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un
, "mono_fclt_un", FALSE
);
4148 register_icall (mono_fload_r4
, "mono_fload_r4", "double ptr", FALSE
);
4149 register_icall (mono_fstore_r4
, "mono_fstore_r4", "void double ptr", FALSE
);
4150 register_icall (mono_fload_r4_arg
, "mono_fload_r4_arg", "uint32 double", FALSE
);
4151 register_icall (mono_isfinite
, "mono_isfinite", "uint32 double", FALSE
);
4154 register_icall (mono_ckfinite
, "mono_ckfinite", "double double", FALSE
);
4156 #ifdef COMPRESSED_INTERFACE_BITMAP
4157 register_icall (mono_class_interface_match
, "mono_class_interface_match", "uint32 ptr int32", TRUE
);
4160 #if SIZEOF_REGISTER == 4
4161 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4
, "mono_fconv_u4", TRUE
);
4163 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "ulong double", mono_fconv_u8
, "mono_fconv_u8", TRUE
);
4166 /* other jit icalls */
4167 register_icall (ves_icall_mono_delegate_ctor
, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE
);
4168 register_icall (mono_class_static_field_address
, "mono_class_static_field_address",
4169 "ptr ptr ptr", FALSE
);
4170 register_icall (mono_ldtoken_wrapper
, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE
);
4171 register_icall (mono_ldtoken_wrapper_generic_shared
, "mono_ldtoken_wrapper_generic_shared",
4172 "ptr ptr ptr ptr", FALSE
);
4173 register_icall (mono_get_special_static_data
, "mono_get_special_static_data", "ptr int", FALSE
);
4174 register_icall (ves_icall_mono_ldstr
, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE
);
4175 register_icall (mono_helper_stelem_ref_check
, "mono_helper_stelem_ref_check", "void object object", FALSE
);
4176 register_icall (ves_icall_object_new
, "ves_icall_object_new", "object ptr ptr", FALSE
);
4177 register_icall (ves_icall_object_new_specific
, "ves_icall_object_new_specific", "object ptr", FALSE
);
4178 register_icall (ves_icall_array_new
, "ves_icall_array_new", "object ptr ptr int32", FALSE
);
4179 register_icall (ves_icall_array_new_specific
, "ves_icall_array_new_specific", "object ptr int32", FALSE
);
4180 register_icall (ves_icall_runtime_class_init
, "ves_icall_runtime_class_init", "void ptr", FALSE
);
4181 register_icall (mono_ldftn
, "mono_ldftn", "ptr ptr", FALSE
);
4182 register_icall (mono_ldvirtfn
, "mono_ldvirtfn", "ptr object ptr", FALSE
);
4183 register_icall (mono_ldvirtfn_gshared
, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE
);
4184 register_icall (mono_helper_compile_generic_method
, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE
);
4185 register_icall (mono_helper_ldstr
, "mono_helper_ldstr", "object ptr int", FALSE
);
4186 register_icall (mono_helper_ldstr_mscorlib
, "mono_helper_ldstr_mscorlib", "object int", FALSE
);
4187 register_icall (mono_helper_newobj_mscorlib
, "mono_helper_newobj_mscorlib", "object int", FALSE
);
4188 register_icall (mono_value_copy
, "mono_value_copy", "void ptr ptr ptr", FALSE
);
4189 register_icall (mono_object_castclass_unbox
, "mono_object_castclass_unbox", "object object ptr", FALSE
);
4190 register_icall (mono_break
, "mono_break", NULL
, TRUE
);
4191 register_icall (mono_create_corlib_exception_0
, "mono_create_corlib_exception_0", "object int", TRUE
);
4192 register_icall (mono_create_corlib_exception_1
, "mono_create_corlib_exception_1", "object int object", TRUE
);
4193 register_icall (mono_create_corlib_exception_2
, "mono_create_corlib_exception_2", "object int object object", TRUE
);
4194 register_icall (mono_array_new_1
, "mono_array_new_1", "object ptr int", FALSE
);
4195 register_icall (mono_array_new_2
, "mono_array_new_2", "object ptr int int", FALSE
);
4196 register_icall (mono_array_new_3
, "mono_array_new_3", "object ptr int int int", FALSE
);
4197 register_icall (mono_array_new_4
, "mono_array_new_4", "object ptr int int int int", FALSE
);
4198 register_icall (mono_get_native_calli_wrapper
, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE
);
4199 register_icall (mono_resume_unwind
, "mono_resume_unwind", "void", TRUE
);
4200 register_icall (mono_gsharedvt_constrained_call
, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE
);
4201 register_icall (mono_gsharedvt_value_copy
, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE
);
4203 register_icall (mono_gc_wbarrier_value_copy_bitmap
, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE
);
4205 register_icall (mono_object_castclass_with_cache
, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE
);
4206 register_icall (mono_object_isinst_with_cache
, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE
);
4207 register_icall (mono_generic_class_init
, "mono_generic_class_init", "void ptr", FALSE
);
4208 register_icall (mono_fill_class_rgctx
, "mono_fill_class_rgctx", "ptr ptr int", FALSE
);
4209 register_icall (mono_fill_method_rgctx
, "mono_fill_method_rgctx", "ptr ptr int", FALSE
);
4211 register_icall (mono_debugger_agent_user_break
, "mono_debugger_agent_user_break", "void", FALSE
);
4213 register_icall (mono_aot_init_llvm_method
, "mono_aot_init_llvm_method", "void ptr int", TRUE
);
4214 register_icall (mono_aot_init_gshared_method_this
, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE
);
4215 register_icall (mono_aot_init_gshared_method_mrgctx
, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE
);
4216 register_icall (mono_aot_init_gshared_method_vtable
, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE
);
4218 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt
, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4219 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt
, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4220 register_icall_no_wrapper (mono_resolve_generic_virtual_call
, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4221 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call
, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4222 /* This needs a wrapper so it can have a preserveall cconv */
4223 register_icall (mono_init_vtable_slot
, "mono_init_vtable_slot", "ptr ptr int", FALSE
);
4224 register_icall (mono_llvmonly_init_delegate
, "mono_llvmonly_init_delegate", "void object", TRUE
);
4225 register_icall (mono_llvmonly_init_delegate_virtual
, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE
);
4226 register_icall (mono_get_assembly_object
, "mono_get_assembly_object", "object ptr", TRUE
);
4227 register_icall (mono_get_method_object
, "mono_get_method_object", "object ptr", TRUE
);
4228 register_icall (mono_throw_method_access
, "mono_throw_method_access", "void ptr ptr", FALSE
);
4229 register_icall_no_wrapper (mono_dummy_jit_icall
, "mono_dummy_jit_icall", "void");
4231 register_icall_with_wrapper (mono_monitor_enter_internal
, "mono_monitor_enter_internal", "void obj");
4232 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, "mono_monitor_enter_v4_internal", "void obj ptr");
4233 register_icall_no_wrapper (mono_monitor_enter_fast
, "mono_monitor_enter_fast", "int obj");
4234 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, "mono_monitor_enter_v4_fast", "int obj ptr");
4237 register_icall (pthread_getspecific
, "pthread_getspecific", "ptr ptr", TRUE
);
4239 /* Register tls icalls */
4240 register_icall_no_wrapper (mono_tls_get_thread
, "mono_tls_get_thread", "ptr");
4241 register_icall_no_wrapper (mono_tls_get_jit_tls
, "mono_tls_get_jit_tls", "ptr");
4242 register_icall_no_wrapper (mono_tls_get_domain
, "mono_tls_get_domain", "ptr");
4243 register_icall_no_wrapper (mono_tls_get_sgen_thread_info
, "mono_tls_get_sgen_thread_info", "ptr");
4244 register_icall_no_wrapper (mono_tls_get_lmf_addr
, "mono_tls_get_lmf_addr", "ptr");
4245 register_icall_no_wrapper (mono_tls_set_thread
, "mono_tls_set_thread", "void ptr");
4246 register_icall_no_wrapper (mono_tls_set_jit_tls
, "mono_tls_set_jit_tls", "void ptr");
4247 register_icall_no_wrapper (mono_tls_set_domain
, "mono_tls_set_domain", "void ptr");
4248 register_icall_no_wrapper (mono_tls_set_sgen_thread_info
, "mono_tls_set_sgen_thread_info", "void ptr");
4249 register_icall_no_wrapper (mono_tls_set_lmf_addr
, "mono_tls_set_lmf_addr", "void ptr");
4252 MonoJitStats mono_jit_stats
= {0};
4255 print_jit_stats (void)
4257 if (mono_jit_stats
.enabled
) {
4258 g_print ("Mono Jit statistics\n");
4259 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/100.0,
4260 mono_jit_stats
.max_ratio_method
);
4261 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats
.biggest_method_size
,
4262 mono_jit_stats
.biggest_method
);
4264 g_print ("Delegates created: %ld\n", mono_stats
.delegate_creations
);
4265 g_print ("Initialized classes: %ld\n", mono_stats
.initialized_class_count
);
4266 g_print ("Used classes: %ld\n", mono_stats
.used_class_count
);
4267 g_print ("Generic vtables: %ld\n", mono_stats
.generic_vtable_count
);
4268 g_print ("Methods: %ld\n", mono_stats
.method_count
);
4269 g_print ("Static data size: %ld\n", mono_stats
.class_static_data_size
);
4270 g_print ("VTable data size: %ld\n", mono_stats
.class_vtable_size
);
4271 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4273 g_print ("\nInitialized classes: %ld\n", mono_stats
.generic_class_count
);
4274 g_print ("Inflated types: %ld\n", mono_stats
.inflated_type_count
);
4275 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4277 g_print ("Sharable generic methods: %ld\n", mono_stats
.generics_sharable_methods
);
4278 g_print ("Unsharable generic methods: %ld\n", mono_stats
.generics_unsharable_methods
);
4279 g_print ("Shared generic methods: %ld\n", mono_stats
.generics_shared_methods
);
4280 g_print ("Shared vtype generic methods: %ld\n", mono_stats
.gsharedvt_methods
);
4282 g_print ("IMT tables size: %ld\n", mono_stats
.imt_tables_size
);
4283 g_print ("IMT number of tables: %ld\n", mono_stats
.imt_number_of_tables
);
4284 g_print ("IMT number of methods: %ld\n", mono_stats
.imt_number_of_methods
);
4285 g_print ("IMT used slots: %ld\n", mono_stats
.imt_used_slots
);
4286 g_print ("IMT colliding slots: %ld\n", mono_stats
.imt_slots_with_collisions
);
4287 g_print ("IMT max collisions: %ld\n", mono_stats
.imt_max_collisions_in_slot
);
4288 g_print ("IMT methods at max col: %ld\n", mono_stats
.imt_method_count_when_max_collisions
);
4289 g_print ("IMT trampolines size: %ld\n", mono_stats
.imt_trampolines_size
);
4291 g_print ("JIT info table inserts: %ld\n", mono_stats
.jit_info_table_insert_count
);
4292 g_print ("JIT info table removes: %ld\n", mono_stats
.jit_info_table_remove_count
);
4293 g_print ("JIT info table lookups: %ld\n", mono_stats
.jit_info_table_lookup_count
);
4295 g_free (mono_jit_stats
.max_ratio_method
);
4296 mono_jit_stats
.max_ratio_method
= NULL
;
4297 g_free (mono_jit_stats
.biggest_method
);
4298 mono_jit_stats
.biggest_method
= NULL
;
4303 mini_cleanup (MonoDomain
*domain
)
4305 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL
)
4306 mono_runtime_shutdown_stat_profiler ();
4309 cominterop_release_all_rcws ();
4312 #ifndef MONO_CROSS_COMPILE
4314 * mono_domain_finalize () needs to be called early since it needs the
4315 * execution engine still fully working (it may invoke managed finalizers).
4317 mono_domain_finalize (domain
, 2000);
4320 /* This accesses metadata so needs to be called before runtime shutdown */
4323 #ifndef MONO_CROSS_COMPILE
4324 mono_runtime_cleanup (domain
);
4327 mono_threadpool_cleanup ();
4329 mono_profiler_shutdown ();
4331 free_jit_tls_data ((MonoJitTlsData
*)mono_tls_get_jit_tls ());
4333 mono_icall_cleanup ();
4335 mono_runtime_cleanup_handlers ();
4337 #ifndef MONO_CROSS_COMPILE
4338 mono_domain_free (domain
, TRUE
);
4343 mono_llvm_cleanup ();
4346 mono_aot_cleanup ();
4348 mono_trampolines_cleanup ();
4350 mono_unwind_cleanup ();
4352 mono_code_manager_destroy (global_codeman
);
4353 g_free (vtable_trampolines
);
4355 mini_jit_cleanup ();
4357 mono_tramp_info_cleanup ();
4359 mono_arch_cleanup ();
4361 mono_generic_sharing_cleanup ();
4365 mono_trace_cleanup ();
4367 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, stdout
);
4369 if (mono_inject_async_exc_method
)
4370 mono_method_desc_free (mono_inject_async_exc_method
);
4372 mono_tls_free_keys ();
4374 mono_os_mutex_destroy (&jit_mutex
);
4376 mono_code_manager_cleanup ();
4379 mono_w32handle_cleanup ();
4384 mono_set_defaults (int verbose_level
, guint32 opts
)
4386 mini_verbose
= verbose_level
;
4387 mono_set_optimizations (opts
);
4391 mono_disable_optimizations (guint32 opts
)
4393 default_opt
&= ~opts
;
4397 mono_set_optimizations (guint32 opts
)
4400 default_opt_set
= TRUE
;
4401 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4402 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
4405 mono_set_generic_sharing_vt_supported (TRUE
);
4410 mono_set_verbose_level (guint32 level
)
4412 mini_verbose
= level
;
4416 * mono_get_runtime_build_info:
4417 * The returned string is owned by the caller. The returned string
4418 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4419 * \returns the runtime version + build date in string format.
4422 mono_get_runtime_build_info (void)
4424 if (mono_build_date
)
4425 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
4427 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
4431 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
4433 GHashTable
*assemblies
= (GHashTable
*)user_data
;
4434 MonoImage
*image
= mono_assembly_get_image (ass
);
4435 MonoMethod
*method
, *invoke
;
4438 if (g_hash_table_lookup (assemblies
, ass
))
4441 g_hash_table_insert (assemblies
, ass
, ass
);
4443 if (mini_verbose
> 0)
4444 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
4446 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
4449 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, &error
);
4451 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
4454 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
4456 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
4460 if (mini_verbose
> 1) {
4461 char * desc
= mono_method_full_name (method
, TRUE
);
4462 g_print ("Compiling %d %s\n", count
, desc
);
4465 mono_compile_method_checked (method
, &error
);
4466 if (!is_ok (&error
)) {
4467 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
4470 if (strcmp (method
->name
, "Finalize") == 0) {
4471 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4472 mono_compile_method_checked (invoke
, &error
);
4473 mono_error_assert_ok (&error
);
4475 #ifndef DISABLE_REMOTING
4476 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature (method
)->hasthis
) {
4477 invoke
= mono_marshal_get_remoting_invoke_with_check (method
);
4478 mono_compile_method_checked (invoke
, &error
);
4479 mono_error_assert_ok (&error
);
4484 /* Load and precompile referenced assemblies as well */
4485 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
4486 mono_assembly_load_reference (image
, i
);
4487 if (image
->references
[i
])
4488 mono_precompile_assembly (image
->references
[i
], assemblies
);
4492 void mono_precompile_assemblies ()
4494 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
4496 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
4498 g_hash_table_destroy (assemblies
);
4503 * Have to export this for AOT.
4506 mono_personality (void)
4509 g_assert_not_reached ();
4512 // Custom handlers currently only implemented by Windows.
4515 mono_runtime_install_custom_handlers (const char *handlers
)
4521 mono_runtime_install_custom_handlers_usage (void)
4524 "Custom Handlers:\n"
4525 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4526 " separated list of available handlers to install.\n"
4528 "No handlers supported on current platform.\n");
4530 #endif /* HOST_WIN32 */