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
28 #include <mono/utils/memcheck.h>
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/assembly-internals.h>
32 #include <mono/metadata/loader.h>
33 #include <mono/metadata/tabledefs.h>
34 #include <mono/metadata/class.h>
35 #include <mono/metadata/object.h>
36 #include <mono/metadata/tokentype.h>
37 #include <mono/metadata/tabledefs.h>
38 #include <mono/metadata/threads.h>
39 #include <mono/metadata/appdomain.h>
40 #include <mono/metadata/debug-helpers.h>
41 #include <mono/metadata/domain-internals.h>
42 #include <mono/metadata/profiler-private.h>
43 #include <mono/metadata/mono-config.h>
44 #include <mono/metadata/environment.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/threads-types.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/runtime.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/metadata/icall-internals.h>
54 #include <mono/metadata/loader-internals.h>
55 #define MONO_MATH_DECLARE_ALL 1
56 #include <mono/utils/mono-math.h>
57 #include <mono/utils/mono-compiler.h>
58 #include <mono/utils/mono-counters.h>
59 #include <mono/utils/mono-error-internals.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-mmap.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-tls.h>
64 #include <mono/utils/mono-hwcap.h>
65 #include <mono/utils/dtrace.h>
66 #include <mono/utils/mono-signal-handler.h>
67 #include <mono/utils/mono-threads.h>
68 #include <mono/utils/mono-threads-coop.h>
69 #include <mono/utils/checked-build.h>
70 #include <mono/utils/mono-compiler.h>
71 #include <mono/utils/mono-proclib.h>
72 #include <mono/utils/mono-state.h>
73 #include <mono/metadata/w32handle.h>
74 #include <mono/metadata/threadpool.h>
77 #include "seq-points.h"
83 #include "aot-compiler.h"
84 #include "aot-runtime.h"
85 #include "llvmonly-runtime.h"
87 #include "jit-icalls.h"
90 #include "mini-llvm.h"
91 #include "debugger-agent.h"
93 #include "mini-runtime.h"
94 #include "interp/interp.h"
96 #ifdef MONO_ARCH_LLVM_SUPPORTED
98 #include "mini-llvm-cpp.h"
102 #include "mono/metadata/icall-signatures.h"
103 #include "mono/utils/mono-tls-inline.h"
105 static guint32 default_opt
= 0;
106 static gboolean default_opt_set
= FALSE
;
107 MonoMethodDesc
*mono_stats_method_desc
;
109 gboolean mono_compile_aot
= FALSE
;
110 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
111 gboolean mono_aot_only
= FALSE
;
112 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
113 gboolean mono_llvm_only
= FALSE
;
114 /* By default, don't require AOT but attempt to probe */
115 MonoAotMode mono_aot_mode
= MONO_AOT_MODE_NORMAL
;
116 MonoEEFeatures mono_ee_features
;
118 const char *mono_build_date
;
119 gboolean mono_do_signal_chaining
;
120 gboolean mono_do_crash_chaining
;
121 int mini_verbose
= 0;
124 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
125 * it can load AOT code compiled by LLVM.
127 gboolean mono_use_llvm
= FALSE
;
129 gboolean mono_use_fast_math
= FALSE
;
131 // Lists of whitelisted and blacklisted CPU features
132 MonoCPUFeatures mono_cpu_features_enabled
= (MonoCPUFeatures
)0;
135 MonoCPUFeatures mono_cpu_features_disabled
= MONO_CPU_X86_FULL_SSEAVX_COMBINED
;
137 MonoCPUFeatures mono_cpu_features_disabled
= (MonoCPUFeatures
)0;
140 gboolean mono_use_interpreter
= FALSE
;
141 const char *mono_interp_opts_string
= NULL
;
143 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
144 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
145 static mono_mutex_t jit_mutex
;
147 static MonoCodeManager
*global_codeman
;
149 MonoDebugOptions mini_debug_options
;
152 #ifdef VALGRIND_JIT_REGISTER_MAP
153 int valgrind_register
;
155 GList
* mono_aot_paths
;
157 static GPtrArray
*profile_options
;
159 static GSList
*tramp_infos
;
160 GSList
*mono_interp_only_classes
;
162 static void register_icalls (void);
165 mono_running_on_valgrind (void)
168 if (RUNNING_ON_VALGRIND
){
169 #ifdef VALGRIND_JIT_REGISTER_MAP
170 valgrind_register
= TRUE
;
179 mono_set_use_llvm (mono_bool use_llvm
)
181 mono_use_llvm
= (gboolean
)use_llvm
;
191 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
193 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
196 ud
->method
= (MonoMethod
*)key
;
201 mono_get_method_from_ip (void *ip
)
207 MonoDomain
*domain
= mono_domain_get ();
208 MonoDebugSourceLocation
*location
;
209 FindTrampUserData user_data
;
212 domain
= mono_get_root_domain ();
214 ji
= mono_jit_info_table_find_internal (domain
, ip
, TRUE
, TRUE
);
217 user_data
.method
= NULL
;
218 mono_domain_lock (domain
);
219 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
220 mono_domain_unlock (domain
);
221 if (user_data
.method
) {
222 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
223 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
229 } else if (ji
->is_trampoline
) {
230 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ji
->d
.tramp_info
->name
);
234 method
= jinfo_get_method (ji
);
235 method_name
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_IL
);
236 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
238 char *file_loc
= NULL
;
240 file_loc
= g_strdup_printf ("[%s :: %du]", location
->source_file
, location
->row
);
242 const char *in_interp
= ji
->is_interp
? " interp" : "";
244 res
= g_strdup_printf (" %s [{%p} + 0x%x%s] %s (%p %p) [%p - %s]", method_name
, method
, (int)((char*)ip
- (char*)ji
->code_start
), in_interp
, file_loc
? file_loc
: "", ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, domain
, domain
->friendly_name
);
246 mono_debug_free_source_location (location
);
247 g_free (method_name
);
255 * \param ip an instruction pointer address
257 * This method is used from a debugger to get the name of the
258 * method at address \p ip. This routine is typically invoked from
259 * a debugger like this:
261 * (gdb) print mono_pmip ($pc)
263 * \returns the name of the method at address \p ip.
268 return mono_get_method_from_ip (ip
);
272 * mono_print_method_from_ip:
273 * \param ip an instruction pointer address
275 * This method is used from a debugger to get the name of the
276 * method at address \p ip.
278 * This prints the name of the method at address \p ip in the standard
279 * output. Unlike \c mono_pmip which returns a string, this routine
280 * prints the value on the standard output.
283 mono_print_method_from_ip (void *ip
)
287 MonoDebugSourceLocation
*source
;
288 MonoDomain
*domain
= mono_domain_get ();
289 MonoDomain
*target_domain
= mono_domain_get ();
290 FindTrampUserData user_data
;
291 MonoGenericSharingContext
*gsctx
;
292 const char *shared_type
;
295 domain
= mono_get_root_domain ();
296 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
297 if (ji
&& ji
->is_trampoline
) {
298 MonoTrampInfo
*tinfo
= ji
->d
.tramp_info
;
300 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
306 user_data
.method
= NULL
;
307 mono_domain_lock (domain
);
308 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
309 mono_domain_unlock (domain
);
311 if (user_data
.method
) {
312 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
313 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
318 g_print ("No method at %p\n", ip
);
322 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
323 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
325 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
328 if (gsctx
->is_gsharedvt
)
329 shared_type
= "gsharedvt ";
331 shared_type
= "gshared ";
334 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
);
337 g_print ("%s:%d\n", source
->source_file
, source
->row
);
340 mono_debug_free_source_location (source
);
345 * mono_method_same_domain:
347 * Determine whenever two compiled methods are in the same domain, thus
348 * the address of the callee can be embedded in the caller.
350 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
354 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
358 * If the call was made from domain-neutral to domain-specific
359 * code, we can't patch the call site.
361 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
364 cmethod
= jinfo_get_method (caller
);
365 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
366 (strstr (cmethod
->name
, "InvokeInDomain"))) {
367 /* The InvokeInDomain methods change the current appdomain */
375 * mono_global_codeman_reserve:
377 * Allocate code memory from the global code manager.
379 void *(mono_global_codeman_reserve
) (int size
)
384 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
386 if (!global_codeman
) {
387 /* This can happen during startup */
388 global_codeman
= mono_code_manager_new ();
389 return mono_code_manager_reserve (global_codeman
, size
);
393 ptr
= mono_code_manager_reserve (global_codeman
, size
);
399 /* The callback shouldn't take any locks */
401 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
404 mono_code_manager_foreach (global_codeman
, func
, user_data
);
409 * mono_create_unwind_op:
411 * Create an unwind op with the given parameters.
414 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
416 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
427 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
429 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
432 res
->has_context
= context
!= NULL
;
434 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
440 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
442 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
446 * mono_tramp_info_create:
448 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
449 * of JI, and UNWIND_OPS.
452 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
454 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
456 info
->name
= g_strdup (name
);
458 info
->code_size
= code_size
;
460 info
->unwind_ops
= unwind_ops
;
466 mono_tramp_info_free (MonoTrampInfo
*info
)
471 mono_free_unwind_info (info
->unwind_ops
);
472 if (info
->owns_uw_info
)
473 g_free (info
->uw_info
);
478 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
482 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
483 mono_jit_info_init (ji
, NULL
, info
->code
, info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
484 ji
->d
.tramp_info
= info
;
485 ji
->is_trampoline
= TRUE
;
487 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
489 mono_jit_info_table_add (domain
, ji
);
493 * mono_tramp_info_register:
495 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
500 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
508 domain
= mono_get_root_domain ();
511 copy
= mono_domain_alloc0 (domain
, sizeof (MonoTrampInfo
));
513 copy
= g_new0 (MonoTrampInfo
, 1);
515 copy
->code
= info
->code
;
516 copy
->code_size
= info
->code_size
;
517 copy
->name
= g_strdup (info
->name
);
519 if (info
->unwind_ops
) {
520 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
521 copy
->owns_uw_info
= TRUE
;
523 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
524 guint8
*temp
= copy
->uw_info
;
525 copy
->uw_info
= mono_domain_alloc (domain
, copy
->uw_info_len
);
526 memcpy (copy
->uw_info
, temp
, copy
->uw_info_len
);
530 /* Trampolines from aot have the unwind ops already encoded */
531 copy
->uw_info
= info
->uw_info
;
532 copy
->uw_info_len
= info
->uw_info_len
;
535 mono_save_trampoline_xdebug_info (info
);
536 mono_lldb_save_trampoline_info (info
);
538 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
540 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
544 /* If no root domain has been created yet, postpone the registration. */
546 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
548 } else if (copy
->uw_info
) {
549 /* Only register trampolines that have unwind infos */
550 register_trampoline_jit_info (domain
, copy
);
553 if (mono_jit_map_is_enabled ())
554 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
556 mono_tramp_info_free (info
);
560 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
562 mono_tramp_info_register_internal (info
, domain
, FALSE
);
566 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
568 mono_tramp_info_register_internal (info
, domain
, TRUE
);
572 mono_tramp_info_cleanup (void)
576 for (l
= tramp_infos
; l
; l
= l
->next
) {
577 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
579 mono_tramp_info_free (info
);
581 g_slist_free (tramp_infos
);
584 /* Register trampolines created before the root domain was created in the jit info tables */
586 register_trampolines (MonoDomain
*domain
)
590 for (l
= tramp_infos
; l
; l
= l
->next
) {
591 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
593 register_trampoline_jit_info (domain
, info
);
597 G_GNUC_UNUSED
static void
603 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
604 * Set a breakpoint in break_count () to break the last time <x> is done.
606 G_GNUC_UNUSED gboolean
607 mono_debug_count (void)
609 static int count
= 0, int_val
= 0;
610 static gboolean inited
, has_value
= FALSE
;
615 char *value
= g_getenv ("COUNT");
617 int_val
= atoi (value
);
627 if (count
== int_val
)
637 mono_icall_get_wrapper_method (MonoJitICallInfo
* callinfo
)
639 /* This icall is used to check for exceptions, so don't check in the wrapper */
640 gboolean check_exc
= (callinfo
!= &mono_get_jit_icall_info ()->mono_thread_interruption_checkpoint
);
642 return mono_marshal_get_icall_wrapper (callinfo
, check_exc
);
646 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
650 gconstpointer addr
, trampoline
;
651 MonoDomain
*domain
= mono_get_root_domain ();
653 if (callinfo
->wrapper
)
654 return callinfo
->wrapper
;
656 wrapper
= mono_icall_get_wrapper_method (callinfo
);
659 addr
= mono_compile_method_checked (wrapper
, error
);
660 mono_error_assert_ok (error
);
661 mono_memory_barrier ();
662 callinfo
->wrapper
= addr
;
665 if (callinfo
->trampoline
)
666 return callinfo
->trampoline
;
667 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, error
);
668 mono_error_assert_ok (error
);
669 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
672 if (!callinfo
->trampoline
) {
673 callinfo
->trampoline
= trampoline
;
675 mono_loader_unlock ();
677 return callinfo
->trampoline
;
682 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
684 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
687 static MonoJitDynamicMethodInfo
*
688 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
690 MonoJitDynamicMethodInfo
*res
;
692 if (domain_jit_info (domain
)->dynamic_code_hash
)
693 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
700 template <typename T
>
702 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, T func
, const char *symbol
, gboolean no_wrapper
)
705 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, gpointer func
, const char *symbol
, gboolean no_wrapper
)
709 mini_register_opcode_emulation (opcode
, jit_icall_info
, name
, sig
, func
, symbol
, no_wrapper
);
711 // FIXME ifdef in mini_register_opcode_emulation and just call it.
713 g_assert (!sig
->hasthis
);
714 g_assert (sig
->param_count
< 3);
716 mono_register_jit_icall_info (jit_icall_info
, func
, name
, sig
, no_wrapper
, symbol
);
720 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
721 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
724 * For JIT icalls implemented in C.
725 * NAME should be the same as the name of the C function whose address is FUNC.
726 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
727 * can't throw exceptions.
729 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
730 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
732 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
733 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
734 * must be extern "C".
736 #define register_icall(func, sig, avoid_wrapper) \
737 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
739 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
740 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
743 * Register an icall where FUNC is dynamically generated or otherwise not
744 * possible to link to it using NAME during AOT.
746 * func is an expression, such a local variable or a function call to get a function pointer.
747 * name is an identifier
749 * Providing func and name separately is what distinguishes "dyn" from regular.
751 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
753 #define register_dyn_icall(func, name, sig, save) \
754 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
759 MonoJitTlsData
*jit_tls
;
761 if ((jit_tls
= mono_tls_get_jit_tls ()))
764 * We do not assert here because this function can be called from
765 * mini-gc.c on a thread that has not executed any managed code, yet
766 * (the thread object allocation can trigger a collection).
772 mono_set_lmf (MonoLMF
*lmf
)
774 (*mono_get_lmf_addr ()) = lmf
;
778 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
780 MonoThreadInfo
*info
;
782 mono_tls_set_jit_tls (jit_tls
);
784 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
785 info
= mono_thread_info_current ();
787 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
791 mono_set_lmf_addr (MonoLMF
**lmf_addr
)
793 MonoThreadInfo
*info
;
795 mono_tls_set_lmf_addr (lmf_addr
);
797 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
798 info
= mono_thread_info_current ();
800 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
806 * Push an MonoLMFExt frame on the LMF stack.
809 mono_push_lmf (MonoLMFExt
*ext
)
813 lmf_addr
= mono_get_lmf_addr ();
815 ext
->lmf
.previous_lmf
= *lmf_addr
;
816 /* Mark that this is a MonoLMFExt */
817 ext
->lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
->lmf
.previous_lmf
) | 2);
819 mono_set_lmf ((MonoLMF
*)ext
);
825 * Pop the last frame from the LMF stack.
828 mono_pop_lmf (MonoLMF
*lmf
)
830 mono_set_lmf ((MonoLMF
*)(((gssize
)lmf
->previous_lmf
) & ~3));
834 * mono_jit_thread_attach:
836 * Called by Xamarin.Mac and other products. Attach thread to runtime if
837 * needed and switch to @domain.
839 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
841 * If the thread is newly-attached, put into GC Safe mode.
843 * @return the original domain which needs to be restored, or NULL.
846 mono_jit_thread_attach (MonoDomain
*domain
)
852 /* Happens when called from AOTed code which is only used in the root domain. */
853 domain
= mono_get_root_domain ();
858 attached
= mono_tls_get_jit_tls () != NULL
;
861 mono_thread_attach (domain
);
864 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
866 /* mono_jit_thread_attach is external-only and not called by
867 * the runtime on any of our own threads. So if we get here,
868 * the thread is running native code - leave it in GC Safe mode
869 * and leave it to the n2m invoke wrappers or MONO_API entry
870 * points to switch to GC Unsafe.
872 MONO_STACKDATA (stackdata
);
873 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata
);
876 orig
= mono_domain_get ();
878 mono_domain_set_fast (domain
, TRUE
);
880 return orig
!= domain
? orig
: NULL
;
884 * mono_jit_set_domain:
886 * Set domain to @domain if @domain is not null
889 mono_jit_set_domain (MonoDomain
*domain
)
891 g_assert (!mono_threads_is_blocking_transition_enabled ());
894 mono_domain_set_fast (domain
, TRUE
);
899 * \param obj exception object
900 * Abort the thread, print exception information and stack trace
903 mono_thread_abort (MonoObject
*obj
)
905 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
907 /* handle_remove should be eventually called for this thread, too
910 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
911 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
) ||
912 ((obj
->vtable
->klass
) == mono_class_try_get_appdomain_unloaded_exception_class () &&
913 mono_thread_info_current ()->runtime_thread
)) {
916 mono_invoke_unhandled_exception_hook (obj
);
920 static MonoJitTlsData
*
921 setup_jit_tls_data (gpointer stack_start
, MonoAbortFunction abort_func
)
923 MonoJitTlsData
*jit_tls
;
926 jit_tls
= mono_tls_get_jit_tls ();
930 jit_tls
= g_new0 (MonoJitTlsData
, 1);
932 jit_tls
->abort_func
= abort_func
;
933 jit_tls
->end_of_stack
= stack_start
;
935 mono_set_jit_tls (jit_tls
);
937 lmf
= g_new0 (MonoLMF
, 1);
938 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
940 jit_tls
->first_lmf
= lmf
;
942 mono_set_lmf_addr (&jit_tls
->lmf
);
946 #ifdef MONO_ARCH_HAVE_TLS_INIT
947 mono_arch_tls_init ();
950 mono_setup_altstack (jit_tls
);
956 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
958 //This happens during AOT cuz the thread is never attached
961 mono_free_altstack (jit_tls
);
963 if (jit_tls
->interp_context
)
964 mini_get_interp_callbacks ()->free_context (jit_tls
->interp_context
);
966 g_free (jit_tls
->first_lmf
);
971 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
973 MonoThreadInfo
*thread
;
974 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
975 thread
= mono_thread_info_current_unchecked ();
977 thread
->jit_data
= jit_tls
;
979 mono_arch_cpu_init ();
982 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
985 mono_thread_abort_dummy (MonoObject
*obj
)
987 if (mono_thread_attach_aborted_cb
)
988 mono_thread_attach_aborted_cb (obj
);
990 mono_thread_abort (obj
);
994 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
996 MonoThreadInfo
*thread
;
997 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
998 thread
= mono_thread_info_current_unchecked ();
1000 thread
->jit_data
= jit_tls
;
1002 mono_arch_cpu_init ();
1006 mini_thread_cleanup (MonoNativeThreadId tid
)
1008 MonoJitTlsData
*jit_tls
= NULL
;
1009 MonoThreadInfo
*info
;
1011 info
= mono_thread_info_current_unchecked ();
1013 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1014 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1015 * not a trivial thing.
1017 * The current offender is mono_thread_manage which cleanup threads from the outside.
1019 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
1020 jit_tls
= info
->jit_data
;
1021 info
->jit_data
= NULL
;
1023 mono_set_jit_tls (NULL
);
1025 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1026 if (mono_get_lmf ()) {
1027 mono_set_lmf (NULL
);
1028 mono_set_lmf_addr (NULL
);
1031 info
= mono_thread_info_lookup (tid
);
1033 jit_tls
= info
->jit_data
;
1034 info
->jit_data
= NULL
;
1036 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1040 free_jit_tls_data (jit_tls
);
1044 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
1046 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
1050 ji
->data
.target
= target
;
1056 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1058 static const char* const patch_info_str
[] = {
1059 #define PATCH_INFO(a,b) "" #a,
1060 #include "patch-info.h"
1065 mono_ji_type_to_string (MonoJumpInfoType type
)
1067 return patch_info_str
[type
];
1071 mono_print_ji (const MonoJumpInfo
*ji
)
1073 const char *type
= patch_info_str
[ji
->type
];
1075 case MONO_PATCH_INFO_RGCTX_FETCH
:
1076 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1077 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1079 printf ("[%s ", type
);
1080 mono_print_ji (entry
->data
);
1081 printf (" -> %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1084 case MONO_PATCH_INFO_METHOD
:
1085 case MONO_PATCH_INFO_METHODCONST
:
1086 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1087 char *s
= mono_method_get_full_name (ji
->data
.method
);
1088 printf ("[%s %s]", type
, s
);
1092 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1093 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji
->data
.jit_icall_id
)->name
);
1095 case MONO_PATCH_INFO_CLASS
:
1096 case MONO_PATCH_INFO_VTABLE
: {
1097 char *name
= mono_class_full_name (ji
->data
.klass
);
1098 printf ("[%s %s]", type
, name
);
1103 printf ("[%s]", type
);
1111 mono_ji_type_to_string (MonoJumpInfoType type
)
1117 mono_print_ji (const MonoJumpInfo
*ji
)
1124 * mono_patch_info_dup_mp:
1126 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1129 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1131 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1132 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1134 switch (patch_info
->type
) {
1135 case MONO_PATCH_INFO_RVA
:
1136 case MONO_PATCH_INFO_LDSTR
:
1137 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1138 case MONO_PATCH_INFO_LDTOKEN
:
1139 case MONO_PATCH_INFO_DECLSEC
:
1140 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1141 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1143 case MONO_PATCH_INFO_SWITCH
:
1144 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1145 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1146 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1147 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1149 case MONO_PATCH_INFO_RGCTX_FETCH
:
1150 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1151 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1152 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1153 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1155 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1156 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1157 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1159 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1160 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1161 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1163 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1164 MonoGSharedVtMethodInfo
*info
;
1165 MonoGSharedVtMethodInfo
*oinfo
;
1168 oinfo
= patch_info
->data
.gsharedvt_method
;
1169 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1170 res
->data
.gsharedvt_method
= info
;
1171 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1172 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1173 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1174 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1175 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1177 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1179 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1180 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1183 case MONO_PATCH_INFO_VIRT_METHOD
: {
1184 MonoJumpInfoVirtMethod
*info
;
1185 MonoJumpInfoVirtMethod
*oinfo
;
1187 oinfo
= patch_info
->data
.virt_method
;
1188 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1189 res
->data
.virt_method
= info
;
1190 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1201 mono_patch_info_hash (gconstpointer data
)
1203 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1204 const MonoJumpInfoType type
= ji
->type
;
1205 guint hash
= type
<< 8;
1208 case MONO_PATCH_INFO_RVA
:
1209 case MONO_PATCH_INFO_LDSTR
:
1210 case MONO_PATCH_INFO_LDTOKEN
:
1211 case MONO_PATCH_INFO_DECLSEC
:
1212 return hash
| ji
->data
.token
->token
;
1213 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1214 return hash
| ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1215 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: // Hash on the selector name
1216 case MONO_PATCH_INFO_LDSTR_LIT
:
1217 return g_str_hash (ji
->data
.name
);
1218 case MONO_PATCH_INFO_VTABLE
:
1219 case MONO_PATCH_INFO_CLASS
:
1220 case MONO_PATCH_INFO_IID
:
1221 case MONO_PATCH_INFO_ADJUSTED_IID
:
1222 case MONO_PATCH_INFO_METHODCONST
:
1223 case MONO_PATCH_INFO_METHOD
:
1224 case MONO_PATCH_INFO_METHOD_JUMP
:
1225 case MONO_PATCH_INFO_METHOD_FTNDESC
:
1226 case MONO_PATCH_INFO_IMAGE
:
1227 case MONO_PATCH_INFO_ICALL_ADDR
:
1228 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1229 case MONO_PATCH_INFO_FIELD
:
1230 case MONO_PATCH_INFO_SFLDA
:
1231 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1232 case MONO_PATCH_INFO_METHOD_RGCTX
:
1233 case MONO_PATCH_INFO_SIGNATURE
:
1234 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1235 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1236 return hash
| (gssize
)ji
->data
.target
;
1237 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1238 return hash
| (gssize
)ji
->data
.gsharedvt
->method
;
1239 case MONO_PATCH_INFO_RGCTX_FETCH
:
1240 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1241 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1242 hash
|= e
->in_mrgctx
| e
->info_type
| mono_patch_info_hash (e
->data
);
1244 return hash
| (gssize
)e
->d
.method
;
1246 return hash
| (gssize
)e
->d
.klass
;
1248 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1249 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1250 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1251 case MONO_PATCH_INFO_GC_NURSERY_START
:
1252 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1253 case MONO_PATCH_INFO_GOT_OFFSET
:
1254 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1255 case MONO_PATCH_INFO_AOT_MODULE
:
1256 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
:
1257 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
:
1258 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES
:
1259 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE
:
1261 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1262 return hash
| ji
->data
.uindex
;
1263 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1264 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1265 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1266 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1267 return hash
| ji
->data
.index
;
1268 case MONO_PATCH_INFO_SWITCH
:
1269 return hash
| ji
->data
.table
->table_size
;
1270 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1271 return hash
| (gssize
)ji
->data
.gsharedvt_method
->method
;
1272 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1273 return hash
| (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1274 case MONO_PATCH_INFO_VIRT_METHOD
: {
1275 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1277 return hash
| (gssize
)info
->klass
| (gssize
)info
->method
;
1279 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1280 return hash
| mono_signature_hash (ji
->data
.sig
);
1281 case MONO_PATCH_INFO_R8_GOT
:
1282 return hash
| (guint32
)*(double*)ji
->data
.target
;
1283 case MONO_PATCH_INFO_R4_GOT
:
1284 return hash
| (guint32
)*(float*)ji
->data
.target
;
1286 printf ("info type: %d\n", ji
->type
);
1287 mono_print_ji (ji
); printf ("\n");
1288 g_assert_not_reached ();
1289 case MONO_PATCH_INFO_NONE
:
1295 * mono_patch_info_equal:
1297 * This might fail to recognize equivalent patches, i.e. floats, so its only
1298 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1302 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1304 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1305 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1307 MonoJumpInfoType
const ji1_type
= ji1
->type
;
1308 MonoJumpInfoType
const ji2_type
= ji2
->type
;
1310 if (ji1_type
!= ji2_type
)
1314 case MONO_PATCH_INFO_RVA
:
1315 case MONO_PATCH_INFO_LDSTR
:
1316 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1317 case MONO_PATCH_INFO_LDTOKEN
:
1318 case MONO_PATCH_INFO_DECLSEC
:
1319 return ji1
->data
.token
->image
== ji2
->data
.token
->image
&&
1320 ji1
->data
.token
->token
== ji2
->data
.token
->token
&&
1321 ji1
->data
.token
->has_context
== ji2
->data
.token
->has_context
&&
1322 ji1
->data
.token
->context
.class_inst
== ji2
->data
.token
->context
.class_inst
&&
1323 ji1
->data
.token
->context
.method_inst
== ji2
->data
.token
->context
.method_inst
;
1324 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1325 case MONO_PATCH_INFO_LDSTR_LIT
:
1326 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1327 case MONO_PATCH_INFO_RGCTX_FETCH
:
1328 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1329 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1330 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1332 return e1
->d
.method
== e2
->d
.method
&& e1
->d
.klass
== e2
->d
.klass
&& e1
->in_mrgctx
== e2
->in_mrgctx
&& e1
->info_type
== e2
->info_type
&& mono_patch_info_equal (e1
->data
, e2
->data
);
1334 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1335 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1336 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1338 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1340 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1341 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1342 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1343 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
;
1344 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1345 return ji1
->data
.uindex
== ji2
->data
.uindex
;
1346 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1347 return ji1
->data
.index
== ji2
->data
.index
;
1348 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1349 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1350 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1351 return ji1
->data
.jit_icall_id
== ji2
->data
.jit_icall_id
;
1352 case MONO_PATCH_INFO_VIRT_METHOD
:
1353 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1354 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1355 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
);
1356 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1357 case MONO_PATCH_INFO_NONE
:
1363 return ji1
->data
.target
== ji2
->data
.target
;
1367 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1369 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1370 gconstpointer target
= NULL
;
1374 switch (patch_info
->type
) {
1375 case MONO_PATCH_INFO_BB
:
1377 * FIXME: This could be hit for methods without a prolog. Should use -1
1378 * but too much code depends on a 0 initial value.
1380 //g_assert (patch_info->data.bb->native_offset);
1381 target
= patch_info
->data
.bb
->native_offset
+ code
;
1383 case MONO_PATCH_INFO_ABS
:
1384 target
= patch_info
->data
.target
;
1386 case MONO_PATCH_INFO_LABEL
:
1387 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1389 case MONO_PATCH_INFO_IP
:
1392 case MONO_PATCH_INFO_JIT_ICALL_ID
: {
1393 MonoJitICallInfo
* const mi
= mono_find_jit_icall_info (patch_info
->data
.jit_icall_id
);
1394 target
= mono_icall_get_wrapper (mi
);
1397 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1398 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
: {
1399 MonoJitICallInfo
* const mi
= mono_find_jit_icall_info (patch_info
->data
.jit_icall_id
);
1403 case MONO_PATCH_INFO_METHOD_JUMP
:
1404 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1408 case MONO_PATCH_INFO_METHOD
:
1409 if (patch_info
->data
.method
== method
) {
1412 /* get the trampoline to the method from the domain */
1413 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1418 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1420 * Return an ftndesc for either AOTed code, or for an interp entry.
1422 target
= mini_llvmonly_load_method_ftndesc (patch_info
->data
.method
, FALSE
, FALSE
, error
);
1423 return_val_if_nok (error
, NULL
);
1426 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1429 mono_domain_lock (domain
);
1430 if (!domain_jit_info (domain
)->method_code_hash
)
1431 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1432 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1434 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1435 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1437 mono_domain_unlock (domain
);
1441 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1442 target
= (gpointer
)&mono_polling_required
;
1444 case MONO_PATCH_INFO_SWITCH
: {
1445 gpointer
*jump_table
;
1447 if (method
&& method
->dynamic
) {
1448 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1450 if (mono_aot_only
) {
1451 jump_table
= (void **)mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1453 jump_table
= (void **)mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1457 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1458 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1461 target
= jump_table
;
1464 case MONO_PATCH_INFO_METHODCONST
:
1465 case MONO_PATCH_INFO_CLASS
:
1466 case MONO_PATCH_INFO_IMAGE
:
1467 case MONO_PATCH_INFO_FIELD
:
1468 case MONO_PATCH_INFO_SIGNATURE
:
1469 case MONO_PATCH_INFO_AOT_MODULE
:
1470 target
= patch_info
->data
.target
;
1472 case MONO_PATCH_INFO_IID
:
1473 mono_class_init_internal (patch_info
->data
.klass
);
1474 target
= GUINT_TO_POINTER (m_class_get_interface_id (patch_info
->data
.klass
));
1476 case MONO_PATCH_INFO_ADJUSTED_IID
:
1477 mono_class_init_internal (patch_info
->data
.klass
);
1478 target
= GUINT_TO_POINTER ((guint32
)(-((m_class_get_interface_id (patch_info
->data
.klass
) + 1) * TARGET_SIZEOF_VOID_P
)));
1480 case MONO_PATCH_INFO_VTABLE
:
1481 target
= mono_class_vtable_checked (domain
, patch_info
->data
.klass
, error
);
1482 mono_error_assert_ok (error
);
1484 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1485 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1487 if (del_tramp
->is_virtual
)
1488 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1490 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1493 case MONO_PATCH_INFO_SFLDA
: {
1494 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, patch_info
->data
.field
->parent
, error
);
1495 mono_error_assert_ok (error
);
1497 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1498 gpointer addr
= NULL
;
1500 mono_domain_lock (domain
);
1501 if (domain
->special_static_fields
)
1502 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1503 mono_domain_unlock (domain
);
1508 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (!method
|| mono_class_needs_cctor_run (vtable
->klass
, method
)))
1509 /* Done by the generated code */
1513 if (!mono_runtime_class_init_full (vtable
, error
)) {
1518 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1521 case MONO_PATCH_INFO_RVA
: {
1522 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1525 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1526 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1529 case MONO_PATCH_INFO_R4
:
1530 case MONO_PATCH_INFO_R4_GOT
:
1531 case MONO_PATCH_INFO_R8
:
1532 case MONO_PATCH_INFO_R8_GOT
:
1533 target
= patch_info
->data
.target
;
1535 case MONO_PATCH_INFO_EXC_NAME
:
1536 target
= patch_info
->data
.name
;
1538 case MONO_PATCH_INFO_LDSTR
:
1540 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1541 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1543 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1545 MonoClass
*handle_class
;
1547 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1548 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1551 mono_class_init_internal (handle_class
);
1552 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType
*)handle
));
1554 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1559 case MONO_PATCH_INFO_LDTOKEN
: {
1561 MonoClass
*handle_class
;
1563 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1564 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1565 mono_error_assert_msg_ok (error
, "Could not patch ldtoken");
1566 mono_class_init_internal (handle_class
);
1571 case MONO_PATCH_INFO_DECLSEC
:
1572 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1574 case MONO_PATCH_INFO_ICALL_ADDR
:
1575 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1576 /* run_cctors == 0 -> AOT */
1577 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1579 target
= mono_lookup_pinvoke_call_internal (patch_info
->data
.method
, error
);
1583 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
));
1589 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1591 if (mono_is_missing_icall_addr (target
) && run_cctors
)
1592 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1595 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1596 target
= &mono_thread_interruption_request_flag
;
1598 case MONO_PATCH_INFO_METHOD_RGCTX
:
1599 target
= mini_method_get_rgctx (patch_info
->data
.method
);
1601 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1602 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1604 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1607 case MONO_PATCH_INFO_BB_OVF
:
1608 case MONO_PATCH_INFO_EXC_OVF
:
1609 case MONO_PATCH_INFO_GOT_OFFSET
:
1610 case MONO_PATCH_INFO_NONE
:
1612 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1613 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1615 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1618 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1619 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1621 /* AOT, not needed */
1624 target
= mono_arch_get_seq_point_info (domain
, code
);
1627 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1628 int card_table_shift_bits
;
1629 gpointer card_table_mask
;
1631 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1634 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1638 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1641 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1645 mono_gc_get_nursery (&shift_bits
, &size
);
1647 target
= (gpointer
)(gssize
)shift_bits
;
1650 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1651 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1654 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1658 case MONO_PATCH_INFO_LDSTR_LIT
: {
1662 len
= strlen ((const char *)patch_info
->data
.target
);
1663 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1664 memcpy (s
, patch_info
->data
.target
, len
);
1669 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1670 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1672 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
: {
1673 target
= (gpointer
) &mono_profiler_state
.gc_allocation_count
;
1676 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
: {
1677 target
= (gpointer
) &mono_profiler_state
.exception_clause_count
;
1680 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES
:
1681 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE
: {
1682 /* Resolved in aot-runtime.c */
1683 g_assert_not_reached ();
1688 g_assert_not_reached ();
1691 return (gpointer
)target
;
1695 * mini_register_jump_site:
1697 * Register IP as a jump/tailcall site which calls METHOD.
1698 * This is needed because common_call_trampoline () cannot patch
1699 * the call site because the caller ip is not available for jumps.
1702 mini_register_jump_site (MonoDomain
*domain
, MonoMethod
*method
, gpointer ip
)
1704 MonoJumpList
*jlist
;
1706 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1707 method
= shared_method
? shared_method
: method
;
1709 mono_domain_lock (domain
);
1710 jlist
= (MonoJumpList
*)g_hash_table_lookup (domain_jit_info (domain
)->jump_target_hash
, method
);
1712 jlist
= (MonoJumpList
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpList
));
1713 g_hash_table_insert (domain_jit_info (domain
)->jump_target_hash
, method
, jlist
);
1715 jlist
->list
= g_slist_prepend (jlist
->list
, ip
);
1716 mono_domain_unlock (domain
);
1720 * mini_patch_jump_sites:
1722 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1725 mini_patch_jump_sites (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1727 GHashTable
*hash
= domain_jit_info (domain
)->jump_target_hash
;
1732 MonoJumpInfo patch_info
;
1733 MonoJumpList
*jlist
;
1736 /* The caller/callee might use different instantiations */
1737 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1738 method
= shared_method
? shared_method
: method
;
1740 mono_domain_lock (domain
);
1741 jlist
= (MonoJumpList
*)g_hash_table_lookup (hash
, method
);
1743 g_hash_table_remove (hash
, method
);
1744 mono_domain_unlock (domain
);
1746 patch_info
.next
= NULL
;
1747 patch_info
.ip
.i
= 0;
1748 patch_info
.type
= MONO_PATCH_INFO_METHOD_JUMP
;
1749 patch_info
.data
.method
= method
;
1751 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1752 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
)
1753 mono_arch_patch_code_new (NULL
, domain
, (guint8
*)tmp
->data
, &patch_info
, addr
);
1755 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1756 // for gshared methods
1757 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
1759 mono_arch_patch_code (NULL
, NULL
, domain
, tmp
->data
, &patch_info
, TRUE
, error
);
1760 mono_error_assert_ok (error
);
1767 * mini_patch_llvm_jit_callees:
1769 * Patch function address slots used by llvm JITed code.
1772 mini_patch_llvm_jit_callees (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1774 if (!domain_jit_info (domain
)->llvm_jit_callees
)
1776 GSList
*callees
= (GSList
*)g_hash_table_lookup (domain_jit_info (domain
)->llvm_jit_callees
, method
);
1779 for (l
= callees
; l
; l
= l
->next
) {
1780 gpointer
*slot
= (gpointer
*)l
->data
;
1787 mini_init_gsctx (MonoDomain
*domain
, MonoMemPool
*mp
, MonoGenericContext
*context
, MonoGenericSharingContext
*gsctx
)
1789 MonoGenericInst
*inst
;
1792 memset (gsctx
, 0, sizeof (MonoGenericSharingContext
));
1794 if (context
&& context
->class_inst
) {
1795 inst
= context
->class_inst
;
1796 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1797 MonoType
*type
= inst
->type_argv
[i
];
1799 if (mini_is_gsharedvt_gparam (type
))
1800 gsctx
->is_gsharedvt
= TRUE
;
1803 if (context
&& context
->method_inst
) {
1804 inst
= context
->method_inst
;
1806 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1807 MonoType
*type
= inst
->type_argv
[i
];
1809 if (mini_is_gsharedvt_gparam (type
))
1810 gsctx
->is_gsharedvt
= TRUE
;
1816 * LOCKING: Acquires the jit code hash lock.
1819 mini_lookup_method (MonoDomain
*domain
, MonoMethod
*method
, MonoMethod
*shared
)
1822 static gboolean inited
= FALSE
;
1823 static int lookups
= 0;
1824 static int failed_lookups
= 0;
1826 mono_domain_jit_code_hash_lock (domain
);
1827 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
1828 if (!ji
&& shared
) {
1829 /* Try generic sharing */
1830 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, shared
);
1831 if (ji
&& !ji
->has_generic_jit_info
)
1834 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &lookups
);
1835 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &failed_lookups
);
1843 mono_domain_jit_code_hash_unlock (domain
);
1849 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
1855 ji
= mini_lookup_method (domain
, method
, NULL
);
1858 if (!mono_method_is_generic_sharable (method
, FALSE
))
1860 shared
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
1861 mono_error_assert_ok (error
);
1862 ji
= mini_lookup_method (domain
, method
, shared
);
1869 mini_get_class (MonoMethod
*method
, guint32 token
, MonoGenericContext
*context
)
1874 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1875 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
1877 klass
= mono_class_inflate_generic_class_checked (klass
, context
, error
);
1878 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1881 klass
= mono_class_get_and_inflate_typespec_checked (m_class_get_image (method
->klass
), token
, context
, error
);
1882 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1885 mono_class_init_internal (klass
);
1890 static FILE* perf_map_file
;
1893 mono_enable_jit_map (void)
1895 if (!perf_map_file
) {
1897 g_snprintf (name
, sizeof (name
), "/tmp/perf-%d.map", getpid ());
1899 perf_map_file
= fopen (name
, "w");
1904 mono_emit_jit_tramp (void *start
, int size
, const char *desc
)
1907 fprintf (perf_map_file
, "%" PRIx64
" %x %s\n", (guint64
)(gsize
)start
, size
, desc
);
1911 mono_emit_jit_map (MonoJitInfo
*jinfo
)
1913 if (perf_map_file
) {
1914 char *name
= mono_method_full_name (jinfo_get_method (jinfo
), TRUE
);
1915 mono_emit_jit_tramp (jinfo
->code_start
, jinfo
->code_size
, name
);
1921 mono_jit_map_is_enabled (void)
1923 return perf_map_file
!= NULL
;
1928 #ifdef ENABLE_JIT_DUMP
1929 #include <sys/mman.h>
1930 #include <sys/syscall.h>
1933 static FILE *perf_dump_file
;
1934 static mono_mutex_t perf_dump_mutex
;
1935 static void *perf_dump_mmap_addr
= MAP_FAILED
;
1936 static guint32 perf_dump_pid
;
1939 JIT_DUMP_MAGIC
= 0x4A695444,
1940 JIT_DUMP_VERSION
= 2,
1942 ELF_MACHINE
= EM_386
,
1944 ELF_MACHINE
= EM_X86_64
,
1946 ELF_MACHINE
= EM_ARM
,
1948 ELF_MACHINE
= EM_AARCH64
,
1949 #elif HOST_POWERPC64
1950 ELF_MACHINE
= EM_PPC64
,
1952 ELF_MACHINE
= EM_S390
,
1975 RecordHeader header
;
1982 // Null terminated function name
1984 } JitCodeLoadRecord
;
1986 static void add_file_header_info (FileHeader
*header
);
1987 static guint64
get_time_stamp_ns (void);
1988 static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord
*record
);
1991 mono_enable_jit_dump (void)
1993 if (perf_dump_pid
== 0)
1994 perf_dump_pid
= getpid();
1996 if (!perf_dump_file
) {
1999 memset (&header
, 0, sizeof (header
));
2001 mono_os_mutex_init (&perf_dump_mutex
);
2002 mono_os_mutex_lock (&perf_dump_mutex
);
2004 g_snprintf (name
, sizeof (name
), "/tmp/jit-%d.dump", perf_dump_pid
);
2006 perf_dump_file
= fopen (name
, "w");
2008 add_file_header_info (&header
);
2009 if (perf_dump_file
) {
2010 fwrite (&header
, sizeof (header
), 1, perf_dump_file
);
2011 //This informs perf of the presence of the jitdump file and support for the feature.​
2012 perf_dump_mmap_addr
= mmap (NULL
, sizeof (header
), PROT_READ
| PROT_EXEC
, MAP_PRIVATE
, fileno (perf_dump_file
), 0);
2015 mono_os_mutex_unlock (&perf_dump_mutex
);
2020 add_file_header_info (FileHeader
*header
)
2022 header
->magic
= JIT_DUMP_MAGIC
;
2023 header
->version
= JIT_DUMP_VERSION
;
2024 header
->total_size
= sizeof (header
);
2025 header
->elf_mach
= ELF_MACHINE
;
2027 header
->pid
= perf_dump_pid
;
2028 header
->timestamp
= get_time_stamp_ns ();
2033 get_time_stamp_ns (void)
2036 int result
= clock_gettime (CLOCK_MONOTONIC
, &ts
);
2037 return ts
.tv_sec
* 1000000000ULL + ts
.tv_nsec
;
2041 mono_emit_jit_dump (MonoJitInfo
*jinfo
, gpointer code
)
2043 static uint64_t code_index
;
2045 if (perf_dump_file
) {
2046 JitCodeLoadRecord record
;
2047 size_t nameLen
= strlen (jinfo
->d
.method
->name
);
2048 memset (&record
, 0, sizeof (record
));
2050 add_basic_JitCodeLoadRecord_info (&record
);
2051 record
.header
.total_size
= sizeof (record
) + nameLen
+ 1 + jinfo
->code_size
;
2052 record
.vma
= (guint64
)jinfo
->code_start
;
2053 record
.code_addr
= (guint64
)jinfo
->code_start
;
2054 record
.code_size
= (guint64
)jinfo
->code_size
;
2056 mono_os_mutex_lock (&perf_dump_mutex
);
2058 record
.code_index
= ++code_index
;
2060 // TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held).
2062 record
.header
.timestamp
= get_time_stamp_ns ();
2064 fwrite (&record
, sizeof (record
), 1, perf_dump_file
);
2065 fwrite (jinfo
->d
.method
->name
, nameLen
+ 1, 1, perf_dump_file
);
2066 fwrite (code
, jinfo
->code_size
, 1, perf_dump_file
);
2068 mono_os_mutex_unlock (&perf_dump_mutex
);
2073 add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord
*record
)
2075 record
->header
.id
= JIT_CODE_LOAD
;
2076 record
->header
.timestamp
= get_time_stamp_ns ();
2077 record
->pid
= perf_dump_pid
;
2078 record
->tid
= syscall (SYS_gettid
);
2082 mono_jit_dump_cleanup (void)
2084 if (perf_dump_mmap_addr
!= MAP_FAILED
)
2085 munmap (perf_dump_mmap_addr
, sizeof(FileHeader
));
2087 fclose (perf_dump_file
);
2093 mono_enable_jit_dump (void)
2098 mono_emit_jit_dump (MonoJitInfo
*jinfo
, gpointer code
)
2103 mono_jit_dump_cleanup (void)
2110 no_gsharedvt_in_wrapper (void)
2112 g_assert_not_reached ();
2118 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.
2119 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
2120 Dependency management in this case is too complex to justify implementing it.
2122 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
2125 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
2126 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
2127 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
2128 Maybe pool JitCompilationEntry, specially those with an inited cond var;
2133 int compilation_count
; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
2134 int ref_count
; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
2135 int threads_waiting
; /* Number of threads waiting on this job */
2136 gboolean has_cond
; /* True if @cond was initialized */
2137 gboolean done
; /* True if the method finished JIT'ing */
2138 MonoCoopCond cond
; /* Cond sleeping threads wait one */
2139 } JitCompilationEntry
;
2142 GPtrArray
*in_flight_methods
; //JitCompilationEntry*
2144 } JitCompilationData
;
2147 Timeout, in millisecounds, that we wait other threads to finish JITing.
2148 This value can't be too small or we won't see enough methods being reused and it can't be too big to cause massive stalls due to unforseable circunstances.
2150 #define MAX_JIT_TIMEOUT_MS 1000
2153 static JitCompilationData compilation_data
;
2154 static int jit_methods_waited
, jit_methods_multiple
, jit_methods_overload
, jit_spurious_wakeups_or_timeouts
;
2157 mini_jit_init_job_control (void)
2159 mono_coop_mutex_init (&compilation_data
.lock
);
2160 compilation_data
.in_flight_methods
= g_ptr_array_new ();
2164 lock_compilation_data (void)
2166 mono_coop_mutex_lock (&compilation_data
.lock
);
2170 unlock_compilation_data (void)
2172 mono_coop_mutex_unlock (&compilation_data
.lock
);
2175 static JitCompilationEntry
*
2176 find_method (MonoMethod
*method
, MonoDomain
*domain
)
2179 for (i
= 0; i
< compilation_data
.in_flight_methods
->len
; ++i
){
2180 JitCompilationEntry
*e
= (JitCompilationEntry
*)compilation_data
.in_flight_methods
->pdata
[i
];
2181 if (e
->method
== method
&& e
->domain
== domain
)
2189 add_current_thread (MonoJitTlsData
*jit_tls
)
2191 ++jit_tls
->active_jit_methods
;
2195 unref_jit_entry (JitCompilationEntry
*entry
)
2198 if (entry
->ref_count
)
2200 if (entry
->has_cond
)
2201 mono_coop_cond_destroy (&entry
->cond
);
2206 * Returns true if this method waited successfully for another thread to JIT it
2209 wait_or_register_method_to_compile (MonoMethod
*method
, MonoDomain
*domain
)
2211 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2212 JitCompilationEntry
*entry
;
2214 static gboolean inited
;
2216 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_waited
);
2217 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_multiple
);
2218 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_overload
);
2219 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_spurious_wakeups_or_timeouts
);
2223 lock_compilation_data ();
2225 if (!(entry
= find_method (method
, domain
))) {
2226 entry
= g_new0 (JitCompilationEntry
, 1);
2227 entry
->method
= method
;
2228 entry
->domain
= domain
;
2229 entry
->compilation_count
= entry
->ref_count
= 1;
2230 g_ptr_array_add (compilation_data
.in_flight_methods
, entry
);
2231 g_assert (find_method (method
, domain
) == entry
);
2232 add_current_thread (jit_tls
);
2234 unlock_compilation_data ();
2236 } else if (jit_tls
->active_jit_methods
> 0 || mono_threads_is_current_thread_in_protected_block ()) {
2237 //We can't suspend the current thread if it's already JITing a method.
2238 //Dependency management is too compilated and we want to get rid of this anyways.
2240 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2241 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2243 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2244 ++entry
->compilation_count
;
2245 ++jit_methods_multiple
;
2246 ++jit_tls
->active_jit_methods
;
2248 unlock_compilation_data ();
2251 ++jit_methods_waited
;
2254 if (!entry
->has_cond
) {
2255 mono_coop_cond_init (&entry
->cond
);
2256 entry
->has_cond
= TRUE
;
2260 ++entry
->threads_waiting
;
2262 g_assert (entry
->has_cond
);
2263 mono_coop_cond_timedwait (&entry
->cond
, &compilation_data
.lock
, MAX_JIT_TIMEOUT_MS
);
2264 --entry
->threads_waiting
;
2267 unref_jit_entry (entry
);
2268 unlock_compilation_data ();
2271 //We hit the timeout or a spurious wakeup, fallback to JITing
2272 g_assert (entry
->ref_count
> 1);
2273 unref_jit_entry (entry
);
2274 ++jit_spurious_wakeups_or_timeouts
;
2276 ++entry
->compilation_count
;
2277 ++jit_methods_multiple
;
2278 ++jit_tls
->active_jit_methods
;
2280 unlock_compilation_data ();
2288 unregister_method_for_compile (MonoMethod
*method
, MonoDomain
*target_domain
)
2290 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2292 lock_compilation_data ();
2294 g_assert (jit_tls
->active_jit_methods
> 0);
2295 --jit_tls
->active_jit_methods
;
2297 JitCompilationEntry
*entry
= find_method (method
, target_domain
);
2298 g_assert (entry
); // It would be weird to fail
2301 if (entry
->threads_waiting
) {
2302 g_assert (entry
->has_cond
);
2303 mono_coop_cond_broadcast (&entry
->cond
);
2306 if (--entry
->compilation_count
== 0) {
2307 g_ptr_array_remove (compilation_data
.in_flight_methods
, entry
);
2308 unref_jit_entry (entry
);
2311 unlock_compilation_data ();
2315 create_jit_info_for_trampoline (MonoMethod
*wrapper
, MonoTrampInfo
*info
)
2317 MonoDomain
*domain
= mono_get_root_domain ();
2322 if (info
->uw_info
) {
2323 uw_info
= info
->uw_info
;
2324 info_len
= info
->uw_info_len
;
2326 uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, &info_len
);
2329 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
);
2330 jinfo
->d
.method
= wrapper
;
2331 jinfo
->code_start
= info
->code
;
2332 jinfo
->code_size
= info
->code_size
;
2333 jinfo
->unwind_info
= mono_cache_unwind_info (uw_info
, info_len
);
2342 compile_special (MonoMethod
*method
, MonoDomain
*target_domain
, MonoError
*error
)
2347 if (mono_llvm_only
) {
2348 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2349 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2351 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
) {
2353 * These wrappers are only created for signatures which are in the program, but
2354 * sometimes we load methods too eagerly and have to create them even if they
2355 * will never be called.
2357 return (gpointer
)no_gsharedvt_in_wrapper
;
2362 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
2363 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
2364 MonoMethodPInvoke
* piinfo
= (MonoMethodPInvoke
*) method
;
2366 if (!piinfo
->addr
) {
2367 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
2368 piinfo
->addr
= mono_lookup_internal_call (method
);
2369 else if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
2371 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method
, TRUE
), m_class_get_image (method
->klass
)->name
);
2373 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method
, TRUE
), m_class_get_image (method
->klass
)->name
);
2376 ERROR_DECL (ignored_error
);
2377 mono_lookup_pinvoke_call_internal (method
, ignored_error
);
2378 mono_error_cleanup (ignored_error
);
2382 MonoMethod
*nm
= mono_marshal_get_native_wrapper (method
, TRUE
, mono_aot_only
);
2383 gpointer compiled_method
= mono_jit_compile_method_jit_only (nm
, error
);
2384 return_val_if_nok (error
, NULL
);
2386 code
= mono_get_addr_from_ftnptr (compiled_method
);
2387 jinfo
= mono_jit_info_table_find (target_domain
, code
);
2389 jinfo
= mono_jit_info_table_find (mono_domain_get (), code
);
2391 MONO_PROFILER_RAISE (jit_done
, (method
, jinfo
));
2393 } else if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
2394 const char *name
= method
->name
;
2398 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2399 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
2400 MonoJitICallInfo
*mi
= &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor
;
2402 * We need to make sure this wrapper
2403 * is compiled because it might end up
2404 * in an (M)RGCTX if generic sharing
2405 * is enabled, and would be called
2406 * indirectly. If it were a
2407 * trampoline we'd try to patch that
2408 * indirect call, which is not
2411 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper_full (mi
, TRUE
));
2412 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2413 if (mono_llvm_only
) {
2414 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
2415 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2416 return_val_if_nok (error
, NULL
);
2417 return mono_get_addr_from_ftnptr (compiled_ptr
);
2420 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2421 if (mono_use_interpreter
)
2424 return mono_create_delegate_trampoline (target_domain
, method
->klass
);
2425 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
2426 nm
= mono_marshal_get_delegate_begin_invoke (method
);
2427 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2428 return_val_if_nok (error
, NULL
);
2429 return mono_get_addr_from_ftnptr (compiled_ptr
);
2430 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
2431 nm
= mono_marshal_get_delegate_end_invoke (method
);
2432 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2433 return_val_if_nok (error
, NULL
);
2434 return mono_get_addr_from_ftnptr (compiled_ptr
);
2438 full_name
= mono_method_full_name (method
, TRUE
);
2439 mono_error_set_invalid_program (error
, "Unrecognizable runtime implemented method '%s'", full_name
);
2444 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2445 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2447 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
|| info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_OUT
) {
2448 static MonoTrampInfo
*in_tinfo
, *out_tinfo
;
2449 MonoTrampInfo
*tinfo
;
2451 gboolean is_in
= info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
;
2453 if (is_in
&& in_tinfo
)
2454 return in_tinfo
->code
;
2455 else if (!is_in
&& out_tinfo
)
2456 return out_tinfo
->code
;
2459 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2461 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2463 if (mono_ee_features
.use_aot_trampolines
)
2464 mono_aot_get_trampoline_full (is_in
? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo
);
2466 mono_arch_get_gsharedvt_trampoline (&tinfo
, FALSE
);
2467 jinfo
= create_jit_info_for_trampoline (method
, tinfo
);
2468 mono_jit_info_table_add (mono_get_root_domain (), jinfo
);
2481 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
2483 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
2485 gpointer code
= NULL
, p
;
2486 MonoJitICallInfo
*callinfo
= NULL
;
2487 WrapperInfo
*winfo
= NULL
;
2488 gboolean use_interp
= FALSE
;
2492 if (mono_ee_features
.force_use_interpreter
&& !jit_only
)
2494 if (!use_interp
&& mono_interp_only_classes
) {
2495 for (GSList
*l
= mono_interp_only_classes
; l
; l
= l
->next
) {
2496 if (!strcmp (m_class_get_name (method
->klass
), (char*)l
->data
))
2501 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2507 /* Should be handled by the caller */
2508 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
2511 * ICALL wrappers are handled specially, since there is only one copy of them
2512 * shared by all appdomains.
2514 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2515 winfo
= mono_marshal_get_wrapper_info (method
);
2516 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
2517 callinfo
= mono_find_jit_icall_info (winfo
->d
.icall
.jit_icall_id
);
2519 /* Must be domain neutral since there is only one copy */
2520 opt
|= MONO_OPT_SHARED
;
2522 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2523 opt
&= ~MONO_OPT_SHARED
;
2526 if (opt
& MONO_OPT_SHARED
)
2527 target_domain
= mono_get_root_domain ();
2529 target_domain
= domain
;
2531 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2532 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2535 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
2536 MonoGenericContext
*ctx
= NULL
;
2537 if (method
->is_inflated
)
2538 ctx
= mono_method_get_context (method
);
2539 method
= info
->d
.synchronized_inner
.method
;
2541 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2542 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
2548 info
= lookup_method (target_domain
, method
);
2550 /* We can't use a domain specific method in another domain */
2551 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2554 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2555 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2559 if (!mono_runtime_class_init_full (vtable
, error
))
2561 MONO_PROFILER_RAISE (jit_done
, (method
, info
));
2562 return mono_create_ftnptr (target_domain
, info
->code_start
);
2566 #ifdef MONO_USE_AOT_COMPILER
2567 if (opt
& MONO_OPT_AOT
) {
2568 MonoDomain
*domain
= NULL
;
2570 if (mono_aot_mode
== MONO_AOT_MODE_INTERP
&& method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2571 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2573 if (info
->subtype
== WRAPPER_SUBTYPE_INTERP_IN
|| info
->subtype
== WRAPPER_SUBTYPE_INTERP_LMF
)
2574 /* AOT'd wrappers for interp must be owned by root domain */
2575 domain
= mono_get_root_domain ();
2579 domain
= mono_domain_get ();
2581 mono_class_init_internal (method
->klass
);
2583 code
= mono_aot_get_method (domain
, method
, error
);
2587 if (mono_gc_is_critical_method (method
)) {
2589 * The suspend code needs to be able to lookup these methods by ip in async context,
2590 * so preload their jit info.
2592 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, code
);
2597 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2598 * This is not a problem, since it will be initialized when the method is first
2599 * called by init_method ().
2601 if (!mono_llvm_only
&& !mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2602 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2603 mono_error_assert_ok (error
);
2604 if (!mono_runtime_class_init_full (vtable
, error
))
2614 code
= compile_special (method
, target_domain
, error
);
2620 if (!jit_only
&& !code
&& mono_aot_only
&& mono_use_interpreter
&& method
->wrapper_type
!= MONO_WRAPPER_OTHER
) {
2621 if (mono_llvm_only
) {
2622 /* Signal to the caller that AOTed code is not found */
2625 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2632 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2633 char *full_name
= mono_type_get_full_name (method
->klass
);
2634 mono_error_set_invalid_operation (error
, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name
);
2639 if (mono_aot_only
) {
2640 char *fullname
= mono_method_get_full_name (method
);
2641 mono_error_set_execution_engine (error
, "Attempting to JIT compile method '%s' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.\n", fullname
);
2647 if (wait_or_register_method_to_compile (method
, target_domain
))
2649 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2650 unregister_method_for_compile (method
, target_domain
);
2655 if (!code
&& mono_llvm_only
) {
2656 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2657 g_assert_not_reached ();
2663 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2665 if ((method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
)) {
2669 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2671 MonoJitInfo
*ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2676 p
= mono_create_ftnptr (target_domain
, code
);
2679 // FIXME Locking here is somewhat historical due to mono_register_jit_icall_wrapper taking loader lock.
2680 // atomic_compare_exchange should suffice.
2681 mono_loader_lock ();
2683 if (!callinfo
->wrapper
) {
2684 callinfo
->wrapper
= p
;
2687 mono_loader_unlock ();
2690 // FIXME p or callinfo->wrapper or does not matter?
2695 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2699 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2704 * mono_jit_compile_method_jit_only:
2706 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2709 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2713 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2717 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2719 invalidated_delegate_trampoline (char *desc
)
2721 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2722 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2728 * mono_jit_free_method:
2730 * Free all memory allocated by the JIT for METHOD.
2733 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2735 MonoJitDynamicMethodInfo
*ji
;
2736 gboolean destroy
= TRUE
, removed
;
2737 GHashTableIter iter
;
2738 MonoJumpList
*jlist
;
2739 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2741 g_assert (method
->dynamic
);
2743 if (mono_use_interpreter
) {
2744 mini_get_interp_callbacks ()->free_method (domain
, method
);
2747 mono_domain_lock (domain
);
2748 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2749 mono_domain_unlock (domain
);
2754 mono_debug_remove_method (method
, domain
);
2755 mono_lldb_remove_method (domain
, method
, ji
);
2757 mono_domain_lock (domain
);
2758 g_hash_table_remove (info
->dynamic_code_hash
, method
);
2759 mono_domain_jit_code_hash_lock (domain
);
2760 removed
= mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2762 mono_domain_jit_code_hash_unlock (domain
);
2763 g_hash_table_remove (info
->jump_trampoline_hash
, method
);
2764 g_hash_table_remove (info
->seq_points
, method
);
2766 ji
->ji
->seq_points
= NULL
;
2768 /* requires the domain lock - took above */
2769 mono_conc_hashtable_remove (info
->runtime_invoke_hash
, method
);
2771 /* Remove jump targets in this method */
2772 g_hash_table_iter_init (&iter
, info
->jump_target_hash
);
2773 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2774 GSList
*tmp
, *remove
;
2777 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2778 guint8
*ip
= (guint8
*)tmp
->data
;
2780 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2781 remove
= g_slist_prepend (remove
, tmp
);
2783 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2784 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2786 g_slist_free (remove
);
2788 mono_domain_unlock (domain
);
2790 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2791 if (mini_debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2793 * Instead of freeing the code, change it to call an error routine
2794 * so people can fix their code.
2796 char *type
= mono_type_full_name (m_class_get_byval_arg (method
->klass
));
2797 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2800 mono_arch_invalidate_method (ji
->ji
, (gpointer
)invalidated_delegate_trampoline
, (gpointer
)type_and_method
);
2806 * This needs to be done before freeing code_mp, since the code address is the
2807 * key in the table, so if we free the code_mp first, another thread can grab the
2808 * same code address and replace our entry in the table.
2810 mono_jit_info_table_remove (domain
, ji
->ji
);
2813 mono_code_manager_destroy (ji
->code_mp
);
2818 mono_jit_search_all_backends_for_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**out_ji
)
2823 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
2825 ERROR_DECL (oerror
);
2827 /* Might be AOTed code */
2828 mono_class_init_internal (method
->klass
);
2829 code
= mono_aot_get_method (domain
, method
, oerror
);
2831 mono_error_assert_ok (oerror
);
2832 ji
= mono_jit_info_table_find (domain
, code
);
2834 if (!is_ok (oerror
))
2835 mono_error_cleanup (oerror
);
2837 /* Might be interpreted */
2838 ji
= mini_get_interp_callbacks ()->find_jit_info (domain
, method
);
2848 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2850 MonoDomain
*target_domain
;
2853 if (default_opt
& MONO_OPT_SHARED
)
2854 target_domain
= mono_get_root_domain ();
2856 target_domain
= domain
;
2858 info
= lookup_method (target_domain
, method
);
2860 /* We can't use a domain specific method in another domain */
2861 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2862 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2865 return info
->code_start
;
2874 static guint32 bisect_opt
= 0;
2875 static GHashTable
*bisect_methods_hash
= NULL
;
2878 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2881 char method_name
[2048];
2884 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2885 g_assert (bisect_methods_hash
);
2887 file
= fopen (method_list_filename
, "r");
2890 while (fgets (method_name
, sizeof (method_name
), file
)) {
2891 size_t len
= strlen (method_name
);
2893 g_assert (method_name
[len
- 1] == '\n');
2894 method_name
[len
- 1] = 0;
2895 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2897 g_assert (feof (file
));
2900 gboolean mono_do_single_method_regression
= FALSE
;
2901 guint32 mono_single_method_regression_opt
= 0;
2902 MonoMethod
*mono_current_single_method
;
2903 GSList
*mono_single_method_list
;
2904 GHashTable
*mono_single_method_hash
;
2907 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 opt
)
2911 if (bisect_methods_hash
) {
2912 char *name
= mono_method_full_name (method
, TRUE
);
2913 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2916 return opt
| bisect_opt
;
2918 if (!mono_do_single_method_regression
)
2920 if (!mono_current_single_method
) {
2921 if (!mono_single_method_hash
)
2922 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2923 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2924 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2925 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2929 if (method
== mono_current_single_method
)
2930 return mono_single_method_regression_opt
;
2935 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2937 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
2942 gpointer compiled_method
;
2943 gpointer runtime_invoke
;
2945 MonoDynCallInfo
*dyn_call_info
;
2946 MonoClass
*ret_box_class
;
2947 MonoMethodSignature
*sig
;
2948 gboolean gsharedvt_invoke
;
2949 gboolean use_interp
;
2950 gpointer
*wrapper_arg
;
2951 } RuntimeInvokeInfo
;
2953 static RuntimeInvokeInfo
*
2954 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, gboolean use_interp
, MonoError
*error
)
2957 RuntimeInvokeInfo
*info
= NULL
;
2958 RuntimeInvokeInfo
*ret
= NULL
;
2960 info
= g_new0 (RuntimeInvokeInfo
, 1);
2961 info
->compiled_method
= compiled_method
;
2962 info
->use_interp
= use_interp
;
2963 if (mono_llvm_only
&& method
->string_ctor
)
2964 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
2966 info
->sig
= mono_method_signature_internal (method
);
2968 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
2970 info
->vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2973 g_assert (info
->vtable
);
2975 MonoMethodSignature
*sig
;
2980 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2981 * in full-aot mode, so we use a slower, but more generic wrapper if
2982 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2984 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2985 if (!mono_llvm_only
&& (mono_aot_only
|| mini_debug_options
.dyn_runtime_invoke
)) {
2986 gboolean supported
= TRUE
;
2989 if (method
->string_ctor
)
2990 sig
= mono_marshal_get_string_ctor_signature (method
);
2992 for (i
= 0; i
< sig
->param_count
; ++i
) {
2993 MonoType
*t
= sig
->params
[i
];
2995 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2999 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
3003 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
3004 if (mini_debug_options
.dyn_runtime_invoke
)
3005 g_assert (info
->dyn_call_info
);
3010 ret_type
= sig
->ret
;
3011 switch (ret_type
->type
) {
3012 case MONO_TYPE_VOID
:
3024 case MONO_TYPE_BOOLEAN
:
3025 case MONO_TYPE_CHAR
:
3028 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
3031 info
->ret_box_class
= mono_defaults
.int_class
;
3033 case MONO_TYPE_STRING
:
3034 case MONO_TYPE_CLASS
:
3035 case MONO_TYPE_ARRAY
:
3036 case MONO_TYPE_SZARRAY
:
3037 case MONO_TYPE_OBJECT
:
3039 case MONO_TYPE_GENERICINST
:
3040 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
3041 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
3043 case MONO_TYPE_VALUETYPE
:
3044 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
3047 g_assert_not_reached ();
3051 if (info
->use_interp
) {
3057 if (!info
->dyn_call_info
) {
3058 if (mono_llvm_only
) {
3059 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
3060 g_assert_not_reached ();
3062 info
->gsharedvt_invoke
= TRUE
;
3063 if (!callee_gsharedvt
) {
3064 /* Invoke a gsharedvt out wrapper instead */
3065 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
3066 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
3068 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
3069 info
->wrapper_arg
[0] = mini_llvmonly_add_method_wrappers (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
3071 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
3072 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
3073 g_free (wrapper_sig
);
3075 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
3079 /* Gsharedvt methods can be invoked the same way */
3080 /* The out wrapper has the same signature as the compiled gsharedvt method */
3081 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
3083 info
->wrapper_arg
= (gpointer
*)(mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
);
3085 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
3086 g_free (wrapper_sig
);
3089 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
3102 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
3104 MonoMethodSignature
*sig
= info
->sig
;
3105 MonoDomain
*domain
= mono_domain_get ();
3106 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
3107 gpointer retval_ptr
;
3108 guint8 retval
[256];
3113 g_assert (info
->gsharedvt_invoke
);
3116 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
3117 * The advantage of this is the gsharedvt out wrappers have a reduced set of
3118 * signatures, so we only have to generate runtime invoke wrappers for these
3120 * This code also handles invocation of gsharedvt methods directly, no
3121 * out wrappers are used in that case.
3123 // allocate param_refs = param_count and args = param_count + hasthis + 2.
3124 int const param_count
= sig
->param_count
;
3125 gpointer
* const param_refs
= g_newa (gpointer
, param_count
* 2 + sig
->hasthis
+ 2);
3126 gpointer
* const args
= param_refs
+ param_count
;
3129 * The runtime invoke wrappers expects pointers to primitive types, so have to
3133 args
[pindex
++] = &obj
;
3134 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3135 retval_ptr
= &retval
;
3136 args
[pindex
++] = &retval_ptr
;
3138 for (i
= 0; i
< sig
->param_count
; ++i
) {
3139 MonoType
*t
= sig
->params
[i
];
3141 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
3142 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
3143 guint8
*nullable_buf
;
3146 size
= mono_class_value_size (klass
, NULL
);
3147 nullable_buf
= g_alloca (size
);
3148 g_assert (nullable_buf
);
3150 /* The argument pointed to by params [i] is either a boxed vtype or null */
3151 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
3152 params
[i
] = nullable_buf
;
3155 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
3156 param_refs
[i
] = params
[i
];
3157 params
[i
] = &(param_refs
[i
]);
3159 args
[pindex
++] = ¶ms
[i
];
3161 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
3162 args
[pindex
++] = &info
->wrapper_arg
;
3164 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3166 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
3170 if (sig
->ret
->type
!= MONO_TYPE_VOID
&& info
->ret_box_class
)
3171 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3173 return *(MonoObject
**)retval
;
3177 * mono_jit_runtime_invoke:
3178 * \param method: the method to invoke
3179 * \param obj: this pointer
3180 * \param params: array of parameter values.
3181 * \param exc: Set to the exception raised in the managed method.
3182 * \param error: error or caught exception object
3183 * If \p exc is NULL, \p error is thrown instead.
3184 * If coop is enabled, \p exc argument is ignored -
3185 * all exceptions are caught and propagated through \p error
3188 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
3190 MonoMethod
*invoke
, *callee
;
3191 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
3192 MonoDomain
*domain
= mono_domain_get ();
3193 MonoJitDomainInfo
*domain_info
;
3194 RuntimeInvokeInfo
*info
, *info2
;
3195 MonoJitInfo
*ji
= NULL
;
3196 gboolean callee_gsharedvt
= FALSE
;
3198 if (mono_ee_features
.force_use_interpreter
)
3199 return mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3205 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
3206 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3210 domain_info
= domain_jit_info (domain
);
3212 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
3215 if (mono_security_core_clr_enabled ()) {
3217 * This might be redundant since mono_class_vtable () already does this,
3218 * but keep it just in case for moonlight.
3220 mono_class_setup_vtable (method
->klass
);
3221 if (mono_class_has_failure (method
->klass
)) {
3222 mono_error_set_for_class_failure (error
, method
->klass
);
3224 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
3229 gpointer compiled_method
;
3232 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3233 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3235 * Array Get/Set/Address methods. The JIT implements them using inline code
3236 * inside the runtime invoke wrappers, so no need to compile them.
3238 if (mono_aot_only
) {
3240 * Call a wrapper, since the runtime invoke wrapper was not generated.
3242 MonoMethod
*wrapper
;
3244 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
3245 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
3252 gboolean use_interp
= FALSE
;
3255 compiled_method
= mono_jit_compile_method_jit_only (callee
, error
);
3256 if (!compiled_method
) {
3257 g_assert (!is_ok (error
));
3259 if (mono_use_interpreter
)
3264 if (mono_llvm_only
) {
3265 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
3266 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3267 if (callee_gsharedvt
)
3268 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
3271 if (!callee_gsharedvt
)
3272 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
3275 compiled_method
= NULL
;
3278 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, use_interp
, error
);
3282 mono_domain_lock (domain
);
3283 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
3284 mono_domain_unlock (domain
);
3292 * We need this here because mono_marshal_get_runtime_invoke can place
3293 * the helper method in System.Object and not the target class.
3295 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
3297 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3301 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3302 we always catch the exception and propagate it through the MonoError */
3303 gboolean catchExcInMonoError
=
3304 (exc
== NULL
) && mono_threads_are_safepoints_enabled ();
3305 MonoObject
*invoke_exc
= NULL
;
3306 if (catchExcInMonoError
)
3309 /* The wrappers expect this to be initialized to NULL */
3313 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3314 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
= NULL
;
3315 if (info
->dyn_call_info
) {
3316 if (!dyn_runtime_invoke
) {
3317 mono_domain_lock (domain
);
3319 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
3320 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method_jit_only (invoke
, error
);
3321 if (!dyn_runtime_invoke
&& mono_use_interpreter
) {
3322 info
->use_interp
= TRUE
;
3323 info
->dyn_call_info
= NULL
;
3324 } else if (!is_ok (error
)) {
3325 mono_domain_unlock (domain
);
3328 mono_domain_unlock (domain
);
3331 if (info
->dyn_call_info
) {
3332 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
3334 int i
, pindex
, buf_size
;
3336 guint8 retval
[256];
3338 /* Convert the arguments to the format expected by start_dyn_call () */
3339 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
3342 args
[pindex
++] = &obj
;
3343 for (i
= 0; i
< sig
->param_count
; ++i
) {
3344 MonoType
*t
= sig
->params
[i
];
3347 args
[pindex
++] = ¶ms
[i
];
3348 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
3349 args
[pindex
++] = ¶ms
[i
];
3351 args
[pindex
++] = params
[i
];
3355 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3357 buf_size
= mono_arch_dyn_call_get_buf_size (info
->dyn_call_info
);
3358 buf
= g_alloca (buf_size
);
3359 memset (buf
, 0, buf_size
);
3362 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
);
3364 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
3365 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
3367 if (catchExcInMonoError
&& *exc
!= NULL
) {
3368 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3372 if (info
->ret_box_class
)
3373 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3375 return *(MonoObject
**)retval
;
3381 if (info
->use_interp
) {
3382 result
= mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3383 return_val_if_nok (error
, NULL
);
3384 } else if (mono_llvm_only
) {
3385 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
3389 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3391 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
3393 if (catchExcInMonoError
&& *exc
!= NULL
) {
3394 ((MonoException
*)(*exc
))->caught_in_unmanaged
= TRUE
;
3395 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3400 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
3402 MonoException
*exc
= NULL
;
3405 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3406 MONO_SIG_HANDLER_GET_CONTEXT
;
3408 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3410 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3412 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3413 if (mono_arch_is_int_overflow (ctx
, info
))
3415 * The spec says this throws ArithmeticException, but MS throws the derived
3416 * OverflowException.
3418 exc
= mono_get_exception_overflow ();
3420 exc
= mono_get_exception_divide_by_zero ();
3422 exc
= mono_get_exception_divide_by_zero ();
3426 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3429 mono_sigctx_to_monoctx (ctx
, &mctx
);
3430 if (mono_dump_start ())
3431 mono_handle_native_crash (mono_get_signame (SIGFPE
), &mctx
, info
);
3432 if (mono_do_crash_chaining
) {
3433 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3438 mono_arch_handle_exception (ctx
, exc
);
3441 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3444 MONO_SIG_HANDLER_FUNC (, mono_crashing_signal_handler
)
3447 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3448 MONO_SIG_HANDLER_GET_CONTEXT
;
3450 if (mono_runtime_get_no_exec ())
3453 mono_sigctx_to_monoctx (ctx
, &mctx
);
3454 if (mono_dump_start ())
3455 #if defined(HAVE_SIG_INFO) && !defined(HOST_WIN32) // info is a siginfo_t
3456 mono_handle_native_crash (mono_get_signame (info
->si_signo
), &mctx
, info
);
3458 mono_handle_native_crash (mono_get_signame (SIGTERM
), &mctx
, info
);
3460 if (mono_do_crash_chaining
) {
3461 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3466 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3468 #define HAVE_SIG_INFO
3469 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3471 #ifdef MONO_SIG_HANDLER_DEBUG
3472 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3473 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3474 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3475 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3476 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3477 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3483 mono_is_addr_implicit_null_check (void *addr
)
3485 /* implicit null checks are only expected to work on the first page. larger
3486 * offsets are expected to have an explicit null check */
3487 return addr
<= GUINT_TO_POINTER (mono_target_pagesize ());
3490 // This function is separate from mono_sigsegv_signal_handler
3491 // so debug_fault_addr can be seen in debugger stacks.
3492 #ifdef MONO_SIG_HANDLER_DEBUG
3494 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug
)
3496 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3499 MonoJitInfo
*ji
= NULL
;
3500 MonoDomain
*domain
= mono_domain_get ();
3501 gpointer fault_addr
= NULL
;
3504 #if defined(HAVE_SIG_INFO) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3505 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3507 #ifdef HAVE_SIG_INFO
3508 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3512 MONO_SIG_HANDLER_GET_CONTEXT
;
3514 mono_sigctx_to_monoctx (ctx
, &mctx
);
3516 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3517 if (mono_arch_is_single_step_event (info
, ctx
)) {
3518 mini_get_dbg_callbacks ()->single_step_event (ctx
);
3520 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3521 mini_get_dbg_callbacks ()->breakpoint_hit (ctx
);
3526 #if defined(HAVE_SIG_INFO)
3527 #if !defined(HOST_WIN32)
3528 fault_addr
= info
->si_addr
;
3529 if (mono_aot_is_pagefault (info
->si_addr
)) {
3530 mono_aot_handle_pagefault (info
->si_addr
);
3533 int signo
= info
->si_signo
;
3535 int signo
= SIGSEGV
;
3538 /* The thread might no be registered with the runtime */
3539 if (!mono_domain_get () || !jit_tls
) {
3540 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3542 if (mono_dump_start())
3543 mono_handle_native_crash (mono_get_signame (signo
), &mctx
, info
);
3544 if (mono_do_crash_chaining
) {
3545 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3552 ji
= mono_jit_info_table_find_internal (domain
, mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3554 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3555 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3558 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3559 fault_addr
= info
->si_addr
;
3560 if (fault_addr
== NULL
) {
3561 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3564 if (jit_tls
&& jit_tls
->stack_size
&&
3565 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3567 * The hard-guard page has been hit: there is not much we can do anymore
3568 * Print a hopefully clear message and abort.
3570 mono_handle_hard_stack_ovf (jit_tls
, ji
, &mctx
, (guint8
*)info
->si_addr
);
3571 g_assert_not_reached ();
3573 /* The original handler might not like that it is executed on an altstack... */
3574 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3578 /* exceptions-amd64.c handles the check itself */
3579 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3581 if (mono_is_addr_implicit_null_check (info
->si_addr
)) {
3582 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3584 // FIXME: This shouldn't run on the altstack
3585 if (mono_dump_start ())
3586 mono_handle_native_crash (mono_get_signame (SIGSEGV
), &mctx
, info
);
3593 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3596 if (mono_dump_start ())
3597 mono_handle_native_crash (mono_get_signame (SIGSEGV
), &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3599 if (mono_do_crash_chaining
) {
3600 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3605 if (mono_is_addr_implicit_null_check (fault_addr
)) {
3606 mono_arch_handle_exception (ctx
, NULL
);
3608 if (mono_dump_start ())
3609 mono_handle_native_crash (mono_get_signame (SIGSEGV
), &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3614 #ifdef MONO_SIG_HANDLER_DEBUG
3616 // This function is separate from mono_sigsegv_signal_handler_debug
3617 // so debug_fault_addr can be seen in debugger stacks.
3618 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3621 gpointer
const debug_fault_addr
= (gpointer
)MONO_SIG_HANDLER_GET_INFO () ->ep
->ExceptionRecord
->ExceptionInformation
[1];
3622 #elif defined (HAVE_SIG_INFO)
3623 gpointer
const debug_fault_addr
= MONO_SIG_HANDLER_GET_INFO ()->si_addr
;
3625 #error No extra parameter is passed, not even 0, to avoid any confusion.
3627 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG
);
3630 #endif // MONO_SIG_HANDLER_DEBUG
3632 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3635 MONO_SIG_HANDLER_GET_CONTEXT
;
3637 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3639 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3641 mono_arch_handle_exception (ctx
, exc
);
3643 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3646 #ifndef DISABLE_REMOTING
3647 /* mono_jit_create_remoting_trampoline:
3648 * @method: pointer to the method info
3650 * Creates a trampoline which calls the remoting functions. This
3651 * is used in the vtable of transparent proxies.
3653 * Returns: a pointer to the newly created code
3656 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3659 guint8
*addr
= NULL
;
3663 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature_internal (method
)->generic_param_count
) {
3664 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3668 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3669 (mono_method_signature_internal (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3670 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
, error
);
3673 return_val_if_nok (error
, NULL
);
3674 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3675 return_val_if_nok (error
, NULL
);
3676 return mono_get_addr_from_ftnptr (addr
);
3680 static G_GNUC_UNUSED
void
3681 no_imt_trampoline (void)
3683 g_assert_not_reached ();
3686 static G_GNUC_UNUSED
void
3687 no_vcall_trampoline (void)
3689 g_assert_not_reached ();
3692 static gpointer
*vtable_trampolines
;
3693 static int vtable_trampolines_size
;
3696 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3698 int index
= slot_index
+ MONO_IMT_SIZE
;
3701 return mini_llvmonly_get_vtable_trampoline (vt
, slot_index
, index
);
3703 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3704 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3706 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3710 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3711 while (new_size
<= index
)
3713 new_table
= g_new0 (gpointer
, new_size
);
3715 if (vtable_trampolines
)
3716 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3717 g_free (vtable_trampolines
);
3718 mono_memory_barrier ();
3719 vtable_trampolines
= (void **)new_table
;
3720 vtable_trampolines_size
= new_size
;
3725 if (!vtable_trampolines
[index
])
3726 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3727 return vtable_trampolines
[index
];
3731 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3733 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3737 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3742 gpointer
*imt
= (gpointer
*)vt
;
3743 imt
-= MONO_IMT_SIZE
;
3745 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3749 create_delegate_method_ptr (MonoMethod
*method
, MonoError
*error
)
3753 if (method_is_dynamic (method
)) {
3754 /* Creating a trampoline would leak memory */
3755 func
= mono_compile_method_checked (method
, error
);
3756 return_val_if_nok (error
, NULL
);
3758 gpointer trampoline
= mono_runtime_create_jump_trampoline (mono_domain_get (), method
, TRUE
, error
);
3759 return_val_if_nok (error
, NULL
);
3760 func
= mono_create_ftnptr (mono_domain_get (), trampoline
);
3766 mini_init_delegate (MonoDelegateHandle delegate
, MonoError
*error
)
3768 MonoDelegate
*del
= MONO_HANDLE_RAW (delegate
);
3770 if (mono_use_interpreter
) {
3771 mini_get_interp_callbacks ()->init_delegate (del
, error
);
3772 return_if_nok (error
);
3775 if (mono_llvm_only
) {
3776 g_assert (del
->method
);
3777 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3778 del
->method_ptr
= mini_llvmonly_load_method_delegate (del
->method
, FALSE
, FALSE
, &del
->extra_arg
, error
);
3779 } else if (!del
->method_ptr
) {
3780 del
->method_ptr
= create_delegate_method_ptr (del
->method
, error
);
3781 return_if_nok (error
);
3786 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3790 abs_offset
= offset
;
3792 abs_offset
= - abs_offset
;
3793 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ TARGET_SIZEOF_VOID_P
);
3797 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3799 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3802 static guint8
**cache
= NULL
;
3803 static int cache_size
= 0;
3808 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3811 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3812 is_interface
= mono_class_is_interface (method
->klass
);
3813 load_imt_reg
= is_virtual_generic
|| is_interface
;
3816 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
3818 offset
= MONO_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
3820 idx
= (offset
/ TARGET_SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3821 g_assert (idx
>= 0);
3823 /* Resize the cache to idx + 1 */
3824 if (cache_size
< idx
+ 1) {
3826 if (cache_size
< idx
+ 1) {
3828 int new_cache_size
= idx
+ 1;
3830 new_cache
= g_new0 (guint8
*, new_cache_size
);
3832 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3835 mono_memory_barrier ();
3837 cache_size
= new_cache_size
;
3845 /* FIXME Support more cases */
3846 if (mono_ee_features
.use_aot_trampolines
) {
3847 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3848 g_assert (cache
[idx
]);
3850 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3856 * mini_parse_debug_option:
3857 * @option: The option to parse.
3859 * Parses debug options for the mono runtime. The options are the same as for
3860 * the MONO_DEBUG environment variable.
3864 mini_parse_debug_option (const char *option
)
3866 // Empty string is ok as consequence of appending ",foo"
3867 // without first checking for empty.
3871 if (!strcmp (option
, "handle-sigint"))
3872 mini_debug_options
.handle_sigint
= TRUE
;
3873 else if (!strcmp (option
, "keep-delegates"))
3874 mini_debug_options
.keep_delegates
= TRUE
;
3875 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3876 mini_debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3877 else if (!strcmp (option
, "collect-pagefault-stats"))
3878 mini_debug_options
.collect_pagefault_stats
= TRUE
;
3879 else if (!strcmp (option
, "break-on-unverified"))
3880 mini_debug_options
.break_on_unverified
= TRUE
;
3881 else if (!strcmp (option
, "no-gdb-backtrace"))
3882 mini_debug_options
.no_gdb_backtrace
= TRUE
;
3883 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
3884 mini_debug_options
.suspend_on_native_crash
= TRUE
;
3885 else if (!strcmp (option
, "suspend-on-exception"))
3886 mini_debug_options
.suspend_on_exception
= TRUE
;
3887 else if (!strcmp (option
, "suspend-on-unhandled"))
3888 mini_debug_options
.suspend_on_unhandled
= TRUE
;
3889 else if (!strcmp (option
, "dont-free-domains"))
3890 mono_dont_free_domains
= TRUE
;
3891 else if (!strcmp (option
, "dyn-runtime-invoke"))
3892 mini_debug_options
.dyn_runtime_invoke
= TRUE
;
3893 else if (!strcmp (option
, "gdb"))
3894 mini_debug_options
.gdb
= TRUE
;
3895 else if (!strcmp (option
, "lldb"))
3896 mini_debug_options
.lldb
= TRUE
;
3897 else if (!strcmp (option
, "llvm-disable-inlining"))
3898 mini_debug_options
.llvm_disable_inlining
= TRUE
;
3899 else if (!strcmp (option
, "llvm-disable-implicit-null-checks"))
3900 mini_debug_options
.llvm_disable_implicit_null_checks
= TRUE
;
3901 else if (!strcmp (option
, "explicit-null-checks"))
3902 mini_debug_options
.explicit_null_checks
= TRUE
;
3903 else if (!strcmp (option
, "gen-seq-points"))
3904 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
3905 else if (!strcmp (option
, "gen-compact-seq-points"))
3906 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3907 else if (!strcmp (option
, "no-compact-seq-points"))
3908 mini_debug_options
.no_seq_points_compact_data
= TRUE
;
3909 else if (!strcmp (option
, "single-imm-size"))
3910 mini_debug_options
.single_imm_size
= TRUE
;
3911 else if (!strcmp (option
, "init-stacks"))
3912 mini_debug_options
.init_stacks
= TRUE
;
3913 else if (!strcmp (option
, "casts"))
3914 mini_debug_options
.better_cast_details
= TRUE
;
3915 else if (!strcmp (option
, "soft-breakpoints"))
3916 mini_debug_options
.soft_breakpoints
= TRUE
;
3917 else if (!strcmp (option
, "check-pinvoke-callconv"))
3918 mini_debug_options
.check_pinvoke_callconv
= TRUE
;
3919 else if (!strcmp (option
, "use-fallback-tls"))
3920 mini_debug_options
.use_fallback_tls
= TRUE
;
3921 else if (!strcmp (option
, "debug-domain-unload"))
3922 mono_enable_debug_domain_unload (TRUE
);
3923 else if (!strcmp (option
, "partial-sharing"))
3924 mono_set_partial_sharing_supported (TRUE
);
3925 else if (!strcmp (option
, "align-small-structs"))
3926 mono_align_small_structs
= TRUE
;
3927 else if (!strcmp (option
, "native-debugger-break"))
3928 mini_debug_options
.native_debugger_break
= TRUE
;
3929 else if (!strcmp (option
, "disable_omit_fp"))
3930 mini_debug_options
.disable_omit_fp
= TRUE
;
3931 // This is an internal testing feature.
3932 // Every tail. encountered is required to be optimized.
3934 else if (!strcmp (option
, "test-tailcall-require"))
3935 mini_debug_options
.test_tailcall_require
= TRUE
;
3936 else if (!strcmp (option
, "verbose-gdb"))
3937 mini_debug_options
.verbose_gdb
= TRUE
;
3938 else if (!strcmp (option
, "clr-memory-model"))
3939 // FIXME Kill this debug flag
3940 mini_debug_options
.weak_memory_model
= FALSE
;
3941 else if (!strcmp (option
, "weak-memory-model"))
3942 mini_debug_options
.weak_memory_model
= TRUE
;
3943 else if (!strcmp (option
, "top-runtime-invoke-unhandled"))
3944 mini_debug_options
.top_runtime_invoke_unhandled
= TRUE
;
3945 else if (!strncmp (option
, "thread-dump-dir=", 16))
3946 mono_set_thread_dump_dir(g_strdup(option
+ 16));
3947 else if (!strncmp (option
, "aot-skip=", 9)) {
3948 mini_debug_options
.aot_skip_set
= TRUE
;
3949 mini_debug_options
.aot_skip
= atoi (option
+ 9);
3957 mini_parse_debug_options (void)
3959 char *options
= g_getenv ("MONO_DEBUG");
3960 gchar
**args
, **ptr
;
3965 args
= g_strsplit (options
, ",", -1);
3968 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
3969 const char *arg
= *ptr
;
3971 if (!mini_parse_debug_option (arg
)) {
3972 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
3973 // test-tailcall-require is also accepted but not documented.
3974 // empty string is also accepted and ignored as a consequence
3975 // of appending ",foo" without checking for empty.
3976 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', 'thread-dump-dir=DIR', 'no-verbose-gdb', 'llvm_disable_inlining', 'llvm-disable-self-init', 'llvm-disable-implicit-null-checks', 'weak-memory-model'.\n");
3985 mini_get_debug_options (void)
3987 return &mini_debug_options
;
3991 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
3993 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3994 gpointer
* desc
= NULL
;
3996 if ((desc
= (gpointer
*)g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
3998 #if defined(__mono_ppc64__)
3999 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
4005 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
4013 mini_get_addr_from_ftnptr (gpointer descr
)
4015 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4016 return *(gpointer
*)descr
;
4023 register_jit_stats (void)
4025 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
4026 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
4027 mono_counters_register ("Methods from AOT+LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot_llvm
);
4028 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
4029 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
4030 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_interp
);
4031 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_method_to_ir
);
4032 mono_counters_register ("JIT/liveness_handle_exception_clauses", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_liveness_handle_exception_clauses
);
4033 mono_counters_register ("JIT/handle_out_of_line_bblock", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_out_of_line_bblock
);
4034 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_long_opts
);
4035 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_typechecks
);
4036 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop
);
4037 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_emulate_ops
);
4038 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_optimize_branches
);
4039 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_global_vregs
);
4040 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce
);
4041 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_alias_analysis
);
4042 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_if_conversion
);
4043 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_bb_ordering
);
4044 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_compile_dominator_info
);
4045 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_compute_natural_loops
);
4046 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_insert_safepoints
);
4047 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_compute
);
4048 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_cprop
);
4049 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_deadce
);
4050 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_perform_abc_removal
);
4051 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_remove
);
4052 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop2
);
4053 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_global_vregs2
);
4054 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce2
);
4055 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_optimize_branches2
);
4056 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_vtype_opts
);
4057 mono_counters_register ("JIT/decompose_array_access_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_array_access_opts
);
4058 mono_counters_register ("JIT/liveness_handle_exception_clauses2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_liveness_handle_exception_clauses2
);
4059 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_analyze_liveness
);
4060 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_linear_scan
);
4061 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_arch_allocate_vars
);
4062 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_spill_global_vars
);
4063 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop3
);
4064 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce3
);
4065 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_codegen
);
4066 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_create_jit_info
);
4067 mono_counters_register ("JIT/gc_create_gc_map", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_gc_create_gc_map
);
4068 mono_counters_register ("JIT/save_seq_point_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_save_seq_point_info
);
4069 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_time
);
4070 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.basic_blocks
);
4071 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.max_basic_blocks
);
4072 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocate_var
);
4073 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.code_reallocs
);
4074 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_code_size
);
4075 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_seq_points_size
);
4076 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlineable_methods
);
4077 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlined_methods
);
4078 mono_counters_register ("Regvars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.regvars
);
4079 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.locals_stack_size
);
4080 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_lookups
);
4081 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.cil_code_size
);
4082 mono_counters_register ("Native code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.native_code_size
);
4083 mono_counters_register ("Aliases found", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_found
);
4084 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_removed
);
4085 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.loads_eliminated
);
4086 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.stores_eliminated
);
4087 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.optimized_divisions
);
4090 static void runtime_invoke_info_free (gpointer value
);
4093 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
4095 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
4096 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
4098 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
4102 class_method_pair_hash (gconstpointer data
)
4104 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
4106 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
4110 mini_create_jit_domain_info (MonoDomain
*domain
)
4112 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
4114 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4115 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4116 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
4117 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4118 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
4119 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
4120 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4121 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
4122 mono_jit_code_hash_init (&info
->interp_code_hash
);
4124 domain
->runtime_info
= info
;
4128 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
4130 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
4131 g_slist_free ((GSList
*)jlist
->list
);
4135 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
4137 GSList
*list
= (GSList
*)value
;
4138 g_slist_free (list
);
4142 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
4144 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
4145 mono_code_manager_destroy (di
->code_mp
);
4150 runtime_invoke_info_free (gpointer value
)
4152 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
4154 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4155 if (info
->dyn_call_info
)
4156 mono_arch_dyn_call_free (info
->dyn_call_info
);
4162 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
4164 g_slist_free ((GSList
*)value
);
4168 mini_free_jit_domain_info (MonoDomain
*domain
)
4170 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
4172 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
4173 g_hash_table_destroy (info
->jump_target_hash
);
4174 if (info
->jump_target_got_slot_hash
) {
4175 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
4176 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
4178 if (info
->dynamic_code_hash
) {
4179 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
4180 g_hash_table_destroy (info
->dynamic_code_hash
);
4182 g_hash_table_destroy (info
->method_code_hash
);
4183 g_hash_table_destroy (info
->jump_trampoline_hash
);
4184 g_hash_table_destroy (info
->jit_trampoline_hash
);
4185 g_hash_table_destroy (info
->delegate_trampoline_hash
);
4186 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
4187 g_hash_table_destroy (info
->mrgctx_hash
);
4188 g_hash_table_destroy (info
->method_rgctx_hash
);
4189 g_hash_table_destroy (info
->interp_method_pointer_hash
);
4190 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
4191 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
4192 g_hash_table_destroy (info
->seq_points
);
4193 g_hash_table_destroy (info
->arch_seq_points
);
4194 if (info
->agent_info
)
4195 mini_get_dbg_callbacks ()->free_domain_info (domain
);
4196 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
4197 if (info
->llvm_jit_callees
) {
4198 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
4199 g_hash_table_destroy (info
->llvm_jit_callees
);
4201 mono_internal_hash_table_destroy (&info
->interp_code_hash
);
4203 mono_llvm_free_domain_info (domain
);
4206 g_free (domain
->runtime_info
);
4207 domain
->runtime_info
= NULL
;
4212 llvm_init_inner (void)
4214 mono_llvm_init (!mono_compile_aot
);
4222 * Load and initialize LLVM support.
4223 * Return TRUE on success.
4226 mini_llvm_init (void)
4229 static gboolean llvm_inited
;
4230 static gboolean init_result
;
4232 mono_loader_lock_if_inited ();
4234 init_result
= llvm_init_inner ();
4237 mono_loader_unlock_if_inited ();
4245 mini_add_profiler_argument (const char *desc
)
4247 if (!profile_options
)
4248 profile_options
= g_ptr_array_new ();
4250 g_ptr_array_add (profile_options
, (gpointer
) desc
);
4254 const MonoEECallbacks
*mono_interp_callbacks_pointer
;
4257 mini_install_interp_callbacks (const MonoEECallbacks
*cbs
)
4259 mono_interp_callbacks_pointer
= cbs
;
4262 static MonoDebuggerCallbacks dbg_cbs
;
4265 mini_install_dbg_callbacks (MonoDebuggerCallbacks
*cbs
)
4267 g_assert (cbs
->version
== MONO_DBG_CALLBACKS_VERSION
);
4268 memcpy (&dbg_cbs
, cbs
, sizeof (MonoDebuggerCallbacks
));
4271 MonoDebuggerCallbacks
*
4272 mini_get_dbg_callbacks (void)
4278 mono_ee_api_version (void)
4280 return MONO_EE_API_VERSION
;
4284 mono_interp_entry_from_trampoline (gpointer ccontext
, gpointer imethod
)
4286 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext
, imethod
);
4290 mono_interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
4292 mini_get_interp_callbacks ()->to_native_trampoline (addr
, ccontext
);
4296 mini_is_interpreter_enabled (void)
4298 return mono_use_interpreter
;
4302 mono_get_runtime_build_version (void);
4305 mini_init (const char *filename
, const char *runtime_version
)
4310 MonoRuntimeCallbacks callbacks
;
4312 static const MonoThreadInfoRuntimeCallbacks ticallbacks
= {
4313 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK
, mono
)
4316 MONO_VES_INIT_BEGIN ();
4318 CHECKED_MONO_INIT ();
4320 #if defined(__linux__)
4321 if (access ("/proc/self/maps", F_OK
) != 0) {
4322 g_print ("Mono requires /proc to be mounted.\n");
4327 mono_interp_stub_init ();
4328 #ifndef DISABLE_INTERPRETER
4329 if (mono_use_interpreter
)
4330 mono_ee_interp_init (mono_interp_opts_string
);
4333 mono_debugger_agent_stub_init ();
4335 mono_debugger_agent_init ();
4339 mini_get_dbg_callbacks ()->parse_options (sdb_options
);
4341 mono_os_mutex_init_recursive (&jit_mutex
);
4343 mono_cross_helpers_run ();
4345 mono_counters_init ();
4349 mini_jit_init_job_control ();
4351 /* Happens when using the embedding interface */
4352 if (!default_opt_set
)
4353 default_opt
= mono_parse_default_optimizations (NULL
);
4355 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4357 mono_set_generic_sharing_vt_supported (TRUE
);
4360 mono_set_generic_sharing_vt_supported (TRUE
);
4363 mono_tls_init_runtime_keys ();
4365 if (!global_codeman
)
4366 global_codeman
= mono_code_manager_new ();
4368 memset (&callbacks
, 0, sizeof (callbacks
));
4369 callbacks
.create_ftnptr
= mini_create_ftnptr
;
4370 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
4371 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
4372 callbacks
.get_runtime_build_version
= mono_get_runtime_build_version
;
4373 callbacks
.set_cast_details
= mono_set_cast_details
;
4374 callbacks
.debug_log
= mini_get_dbg_callbacks ()->debug_log
;
4375 callbacks
.debug_log_is_enabled
= mini_get_dbg_callbacks ()->debug_log_is_enabled
;
4376 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
4377 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
4378 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
4379 callbacks
.init_delegate
= mini_init_delegate
;
4380 #define JIT_INVOKE_WORKS
4381 #ifdef JIT_INVOKE_WORKS
4382 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
4384 #define JIT_TRAMPOLINES_WORK
4385 #ifdef JIT_TRAMPOLINES_WORK
4386 callbacks
.compile_method
= mono_jit_compile_method
;
4387 callbacks
.create_jump_trampoline
= mono_create_jump_trampoline
;
4388 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
4389 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
4390 callbacks
.free_method
= mono_jit_free_method
;
4391 #ifndef DISABLE_REMOTING
4392 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
4395 #ifndef DISABLE_REMOTING
4396 if (mono_use_interpreter
)
4397 callbacks
.interp_get_remoting_invoke
= mini_get_interp_callbacks ()->get_remoting_invoke
;
4399 callbacks
.is_interpreter_enabled
= mini_is_interpreter_enabled
;
4400 callbacks
.get_weak_field_indexes
= mono_aot_get_weak_field_indexes
;
4402 #ifndef DISABLE_CRASH_REPORTING
4403 callbacks
.install_state_summarizer
= mini_register_sigterm_handler
;
4406 mono_install_callbacks (&callbacks
);
4409 mono_w32handle_init ();
4412 mono_thread_info_runtime_init (&ticallbacks
);
4414 if (g_hasenv ("MONO_DEBUG")) {
4415 mini_parse_debug_options ();
4418 mono_code_manager_init ();
4420 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4422 static const MonoCodeManagerCallbacks code_manager_callbacks
= {
4424 #undef MONO_CODE_MANAGER_CALLBACK
4425 #define MONO_CODE_MANAGER_CALLBACK(ret, name, sig) mono_arch_code_ ## name,
4426 MONO_CODE_MANAGER_CALLBACKS
4430 mono_code_manager_install_callbacks (&code_manager_callbacks
);
4435 mono_arch_cpu_init ();
4439 mono_unwind_init ();
4441 if (mini_debug_options
.lldb
|| g_hasenv ("MONO_LLDB")) {
4442 mono_lldb_init ("");
4443 mono_dont_free_domains
= TRUE
;
4446 #ifdef XDEBUG_ENABLED
4447 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
4449 mono_xdebug_init (mono_xdebug
);
4450 g_free (mono_xdebug
);
4451 /* So methods for multiple domains don't have the same address */
4452 mono_dont_free_domains
= TRUE
;
4453 mono_using_xdebug
= TRUE
;
4454 } else if (mini_debug_options
.gdb
) {
4455 mono_xdebug_init ((char*)"gdb");
4456 mono_dont_free_domains
= TRUE
;
4457 mono_using_xdebug
= TRUE
;
4463 mono_llvm_init (!mono_compile_aot
);
4466 mono_trampolines_init ();
4468 if (default_opt
& MONO_OPT_AOT
)
4471 mini_get_dbg_callbacks ()->init ();
4474 mono_wasm_debugger_init ();
4477 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4478 mono_set_generic_sharing_supported (TRUE
);
4481 mono_thread_info_signals_init ();
4483 mono_init_native_crash_info ();
4485 #ifndef MONO_CROSS_COMPILE
4486 mono_runtime_install_handlers ();
4488 mono_threads_install_cleanup (mini_thread_cleanup
);
4490 #ifdef JIT_TRAMPOLINES_WORK
4491 mono_install_create_domain_hook (mini_create_jit_domain_info
);
4492 mono_install_free_domain_hook (mini_free_jit_domain_info
);
4494 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
4495 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
4496 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
4498 mono_profiler_state
.context_enable
= mini_profiler_context_enable
;
4499 mono_profiler_state
.context_get_this
= mini_profiler_context_get_this
;
4500 mono_profiler_state
.context_get_argument
= mini_profiler_context_get_argument
;
4501 mono_profiler_state
.context_get_local
= mini_profiler_context_get_local
;
4502 mono_profiler_state
.context_get_result
= mini_profiler_context_get_result
;
4503 mono_profiler_state
.context_free_buffer
= mini_profiler_context_free_buffer
;
4505 if (profile_options
)
4506 for (guint i
= 0; i
< profile_options
->len
; i
++)
4507 mono_profiler_load ((const char *) g_ptr_array_index (profile_options
, i
));
4509 mono_profiler_started ();
4511 if (mini_debug_options
.collect_pagefault_stats
)
4512 mono_aot_set_make_unreadable (TRUE
);
4514 if (runtime_version
)
4515 domain
= mono_init_version (filename
, runtime_version
);
4517 domain
= mono_init_from_assembly (filename
, filename
);
4519 if (mono_aot_only
) {
4520 /* This helps catch code allocation requests */
4521 mono_code_manager_set_read_only (domain
->code_mp
);
4522 mono_marshal_use_aot_wrappers (TRUE
);
4525 if (mono_llvm_only
) {
4526 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline
);
4527 mono_set_always_build_imt_trampolines (TRUE
);
4528 } else if (mono_aot_only
) {
4529 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
4531 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
4534 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4535 mono_arch_finish_init ();
4537 /* This must come after mono_init () in the aot-only case */
4538 mono_exceptions_init ();
4540 /* This should come after mono_init () too */
4543 mono_create_icall_signatures ();
4545 register_jit_stats ();
4547 #define JIT_CALLS_WORK
4548 #ifdef JIT_CALLS_WORK
4549 /* Needs to be called here since register_jit_icall depends on it */
4550 mono_marshal_init ();
4552 mono_arch_register_lowlevel_calls ();
4556 mono_generic_sharing_init ();
4559 #ifdef MONO_ARCH_SIMD_INTRINSICS
4560 mono_simd_intrinsics_init ();
4563 mono_tasklets_init ();
4565 register_trampolines (domain
);
4567 if (mono_compile_aot
)
4569 * Avoid running managed code when AOT compiling, since the platform
4570 * might only support aot-only execution.
4572 mono_runtime_set_no_exec (TRUE
);
4574 mono_mem_account_register_counters ();
4576 #define JIT_RUNTIME_WORKS
4577 #ifdef JIT_RUNTIME_WORKS
4578 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
4579 mono_runtime_init_checked (domain
, (MonoThreadStartCB
)mono_thread_start_cb
, mono_thread_attach_cb
, error
);
4580 mono_error_assert_ok (error
);
4581 mono_thread_attach (domain
);
4582 MONO_PROFILER_RAISE (thread_name
, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4584 mono_threads_set_runtime_startup_finished ();
4586 #ifdef ENABLE_EXPERIMENT_TIERED
4587 if (!mono_compile_aot
) {
4588 /* create compilation thread in background */
4589 mini_tiered_init ();
4593 if (mono_profiler_sampling_enabled ())
4594 mono_runtime_setup_stat_profiler ();
4596 MONO_PROFILER_RAISE (runtime_initialized
, ());
4598 MONO_VES_INIT_END ();
4604 register_icalls (void)
4606 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4607 ves_icall_get_frame_info
);
4608 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4609 ves_icall_get_trace
);
4610 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4611 mono_runtime_install_handlers
);
4612 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4613 mono_runtime_cleanup_handlers
);
4615 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4616 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4617 mini_get_dbg_callbacks ()->unhandled_exception
);
4621 * It's important that we pass `TRUE` as the last argument here, as
4622 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4623 * *did* emit a wrapper, we'd be looking at infinite recursion since
4624 * the wrapper would call the icall which would call the wrapper and
4627 register_icall (mono_profiler_raise_method_enter
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4628 register_icall (mono_profiler_raise_method_leave
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4629 register_icall (mono_profiler_raise_method_tail_call
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4630 register_icall (mono_profiler_raise_exception_clause
, mono_icall_sig_void_ptr_int_int_object
, TRUE
);
4632 register_icall (mono_trace_enter_method
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4633 register_icall (mono_trace_leave_method
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4634 g_assert (mono_get_lmf_addr
== mono_tls_get_lmf_addr
);
4635 register_icall (mono_jit_set_domain
, mono_icall_sig_void_ptr
, TRUE
);
4636 register_icall (mono_domain_get
, mono_icall_sig_ptr
, TRUE
);
4638 register_icall (mono_llvm_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4639 register_icall (mono_llvm_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4640 register_icall (mono_llvm_resume_exception
, mono_icall_sig_void
, TRUE
);
4641 register_icall (mono_llvm_match_exception
, mono_icall_sig_int_ptr_int_int_ptr_object
, TRUE
);
4642 register_icall (mono_llvm_clear_exception
, NULL
, TRUE
);
4643 register_icall (mono_llvm_load_exception
, mono_icall_sig_object
, TRUE
);
4644 register_icall (mono_llvm_throw_corlib_exception
, mono_icall_sig_void_int
, TRUE
);
4645 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4646 register_icall (mono_llvm_set_unhandled_exception_handler
, NULL
, TRUE
);
4648 // FIXME: This is broken
4650 register_icall (mono_debug_personality
, mono_icall_sig_int_int_int_ptr_ptr_ptr
, TRUE
);
4654 if (!mono_llvm_only
) {
4655 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4656 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4657 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception
, mono_icall_sig_void_ptr
, TRUE
);
4659 register_icall (mono_thread_get_undeniable_exception
, mono_icall_sig_object
, FALSE
);
4660 register_icall (ves_icall_thread_finish_async_abort
, mono_icall_sig_void
, FALSE
);
4661 register_icall (mono_thread_interruption_checkpoint
, mono_icall_sig_object
, FALSE
);
4662 register_icall (mono_thread_force_interruption_checkpoint_noraise
, mono_icall_sig_object
, FALSE
);
4664 register_icall (mono_threads_state_poll
, mono_icall_sig_void
, FALSE
);
4666 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4667 register_opcode_emulation (OP_LMUL
, __emul_lmul
, mono_icall_sig_long_long_long
, mono_llmult
, FALSE
);
4668 register_opcode_emulation (OP_LDIV
, __emul_ldiv
, mono_icall_sig_long_long_long
, mono_lldiv
, FALSE
);
4669 register_opcode_emulation (OP_LDIV_UN
, __emul_ldiv_un
, mono_icall_sig_long_long_long
, mono_lldiv_un
, FALSE
);
4670 register_opcode_emulation (OP_LREM
, __emul_lrem
, mono_icall_sig_long_long_long
, mono_llrem
, FALSE
);
4671 register_opcode_emulation (OP_LREM_UN
, __emul_lrem_un
, mono_icall_sig_long_long_long
, mono_llrem_un
, FALSE
);
4673 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4674 register_opcode_emulation (OP_LMUL_OVF_UN
, __emul_lmul_ovf_un
, mono_icall_sig_long_long_long
, mono_llmult_ovf_un
, FALSE
);
4675 register_opcode_emulation (OP_LMUL_OVF
, __emul_lmul_ovf
, mono_icall_sig_long_long_long
, mono_llmult_ovf
, FALSE
);
4678 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4679 register_opcode_emulation (OP_LSHL
, __emul_lshl
, mono_icall_sig_long_long_int32
, mono_lshl
, TRUE
);
4680 register_opcode_emulation (OP_LSHR
, __emul_lshr
, mono_icall_sig_long_long_int32
, mono_lshr
, TRUE
);
4681 register_opcode_emulation (OP_LSHR_UN
, __emul_lshr_un
, mono_icall_sig_long_long_int32
, mono_lshr_un
, TRUE
);
4684 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4685 register_opcode_emulation (OP_IDIV
, __emul_op_idiv
, mono_icall_sig_int32_int32_int32
, mono_idiv
, FALSE
);
4686 register_opcode_emulation (OP_IDIV_UN
, __emul_op_idiv_un
, mono_icall_sig_int32_int32_int32
, mono_idiv_un
, FALSE
);
4687 register_opcode_emulation (OP_IREM
, __emul_op_irem
, mono_icall_sig_int32_int32_int32
, mono_irem
, FALSE
);
4688 register_opcode_emulation (OP_IREM_UN
, __emul_op_irem_un
, mono_icall_sig_int32_int32_int32
, mono_irem_un
, FALSE
);
4691 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4692 register_opcode_emulation (OP_IMUL
, __emul_op_imul
, mono_icall_sig_int32_int32_int32
, mono_imul
, TRUE
);
4695 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4696 register_opcode_emulation (OP_IMUL_OVF
, __emul_op_imul_ovf
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf
, FALSE
);
4697 register_opcode_emulation (OP_IMUL_OVF_UN
, __emul_op_imul_ovf_un
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf_un
, FALSE
);
4700 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4701 register_opcode_emulation (OP_FDIV
, __emul_fdiv
, mono_icall_sig_double_double_double
, mono_fdiv
, FALSE
);
4704 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4705 register_opcode_emulation (OP_FCONV_TO_U8
, __emul_fconv_to_u8
, mono_icall_sig_ulong_double
, mono_fconv_u8_2
, FALSE
);
4706 register_opcode_emulation (OP_RCONV_TO_U8
, __emul_rconv_to_u8
, mono_icall_sig_ulong_float
, mono_rconv_u8
, FALSE
);
4708 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4709 register_opcode_emulation (OP_FCONV_TO_U4
, __emul_fconv_to_u4
, mono_icall_sig_uint32_double
, mono_fconv_u4_2
, FALSE
);
4710 register_opcode_emulation (OP_RCONV_TO_U4
, __emul_rconv_to_u4
, mono_icall_sig_uint32_float
, mono_rconv_u4
, FALSE
);
4712 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, __emul_fconv_to_ovf_i8
, mono_icall_sig_long_double
, mono_fconv_ovf_i8
, FALSE
);
4713 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, __emul_fconv_to_ovf_u8
, mono_icall_sig_ulong_double
, mono_fconv_ovf_u8
, FALSE
);
4714 register_opcode_emulation (OP_FCONV_TO_OVF_U8_UN
, __emul_fconv_to_ovf_u8_un
, mono_icall_sig_ulong_double
, mono_fconv_ovf_u8_un
, FALSE
);
4715 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, __emul_rconv_to_ovf_i8
, mono_icall_sig_long_float
, mono_rconv_ovf_i8
, FALSE
);
4716 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, __emul_rconv_to_ovf_u8
, mono_icall_sig_ulong_float
, mono_rconv_ovf_u8
, FALSE
);
4717 register_opcode_emulation (OP_RCONV_TO_OVF_U8_UN
, __emul_rconv_to_ovf_u8_un
, mono_icall_sig_ulong_float
, mono_rconv_ovf_u8_un
, FALSE
);
4719 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4720 register_opcode_emulation (OP_FCONV_TO_I8
, __emul_fconv_to_i8
, mono_icall_sig_long_double
, mono_fconv_i8
, FALSE
);
4721 register_opcode_emulation (OP_RCONV_TO_I8
, __emul_rconv_to_i8
, mono_icall_sig_long_float
, mono_rconv_i8
, FALSE
);
4724 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4725 register_opcode_emulation (OP_ICONV_TO_R_UN
, __emul_iconv_to_r_un
, mono_icall_sig_double_int32
, mono_conv_to_r8_un
, FALSE
);
4727 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4728 register_opcode_emulation (OP_LCONV_TO_R8
, __emul_lconv_to_r8
, mono_icall_sig_double_long
, mono_lconv_to_r8
, FALSE
);
4730 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4731 register_opcode_emulation (OP_LCONV_TO_R4
, __emul_lconv_to_r4
, mono_icall_sig_float_long
, mono_lconv_to_r4
, FALSE
);
4733 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4734 register_opcode_emulation (OP_LCONV_TO_R_UN
, __emul_lconv_to_r8_un
, mono_icall_sig_double_long
, mono_lconv_to_r8_un
, FALSE
);
4736 #ifdef MONO_ARCH_EMULATE_FREM
4737 register_opcode_emulation (OP_FREM
, __emul_frem
, mono_icall_sig_double_double_double
, mono_fmod
, FALSE
);
4738 register_opcode_emulation (OP_RREM
, __emul_rrem
, mono_icall_sig_float_float_float
, fmodf
, FALSE
);
4741 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4742 if (mono_arch_is_soft_float ()) {
4743 register_opcode_emulation (OP_FSUB
, __emul_fsub
, mono_icall_sig_double_double_double
, mono_fsub
, FALSE
);
4744 register_opcode_emulation (OP_FADD
, __emul_fadd
, mono_icall_sig_double_double_double
, mono_fadd
, FALSE
);
4745 register_opcode_emulation (OP_FMUL
, __emul_fmul
, mono_icall_sig_double_double_double
, mono_fmul
, FALSE
);
4746 register_opcode_emulation (OP_FNEG
, __emul_fneg
, mono_icall_sig_double_double
, mono_fneg
, FALSE
);
4747 register_opcode_emulation (OP_ICONV_TO_R8
, __emul_iconv_to_r8
, mono_icall_sig_double_int32
, mono_conv_to_r8
, FALSE
);
4748 register_opcode_emulation (OP_ICONV_TO_R4
, __emul_iconv_to_r4
, mono_icall_sig_double_int32
, mono_conv_to_r4
, FALSE
);
4749 register_opcode_emulation (OP_FCONV_TO_R4
, __emul_fconv_to_r4
, mono_icall_sig_double_double
, mono_fconv_r4
, FALSE
);
4750 register_opcode_emulation (OP_FCONV_TO_I1
, __emul_fconv_to_i1
, mono_icall_sig_int8_double
, mono_fconv_i1
, FALSE
);
4751 register_opcode_emulation (OP_FCONV_TO_I2
, __emul_fconv_to_i2
, mono_icall_sig_int16_double
, mono_fconv_i2
, FALSE
);
4752 register_opcode_emulation (OP_FCONV_TO_I4
, __emul_fconv_to_i4
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4753 register_opcode_emulation (OP_FCONV_TO_U1
, __emul_fconv_to_u1
, mono_icall_sig_uint8_double
, mono_fconv_u1
, FALSE
);
4754 register_opcode_emulation (OP_FCONV_TO_U2
, __emul_fconv_to_u2
, mono_icall_sig_uint16_double
, mono_fconv_u2
, FALSE
);
4756 #if TARGET_SIZEOF_VOID_P == 4
4757 register_opcode_emulation (OP_FCONV_TO_I
, __emul_fconv_to_i
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4760 register_opcode_emulation (OP_FBEQ
, __emul_fcmp_eq
, mono_icall_sig_uint32_double_double
, mono_fcmp_eq
, FALSE
);
4761 register_opcode_emulation (OP_FBLT
, __emul_fcmp_lt
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt
, FALSE
);
4762 register_opcode_emulation (OP_FBGT
, __emul_fcmp_gt
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt
, FALSE
);
4763 register_opcode_emulation (OP_FBLE
, __emul_fcmp_le
, mono_icall_sig_uint32_double_double
, mono_fcmp_le
, FALSE
);
4764 register_opcode_emulation (OP_FBGE
, __emul_fcmp_ge
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge
, FALSE
);
4765 register_opcode_emulation (OP_FBNE_UN
, __emul_fcmp_ne_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ne_un
, FALSE
);
4766 register_opcode_emulation (OP_FBLT_UN
, __emul_fcmp_lt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt_un
, FALSE
);
4767 register_opcode_emulation (OP_FBGT_UN
, __emul_fcmp_gt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt_un
, FALSE
);
4768 register_opcode_emulation (OP_FBLE_UN
, __emul_fcmp_le_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_le_un
, FALSE
);
4769 register_opcode_emulation (OP_FBGE_UN
, __emul_fcmp_ge_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge_un
, FALSE
);
4771 register_opcode_emulation (OP_FCEQ
, __emul_fcmp_ceq
, mono_icall_sig_uint32_double_double
, mono_fceq
, FALSE
);
4772 register_opcode_emulation (OP_FCGT
, __emul_fcmp_cgt
, mono_icall_sig_uint32_double_double
, mono_fcgt
, FALSE
);
4773 register_opcode_emulation (OP_FCGT_UN
, __emul_fcmp_cgt_un
, mono_icall_sig_uint32_double_double
, mono_fcgt_un
, FALSE
);
4774 register_opcode_emulation (OP_FCLT
, __emul_fcmp_clt
, mono_icall_sig_uint32_double_double
, mono_fclt
, FALSE
);
4775 register_opcode_emulation (OP_FCLT_UN
, __emul_fcmp_clt_un
, mono_icall_sig_uint32_double_double
, mono_fclt_un
, FALSE
);
4777 register_icall (mono_fload_r4
, mono_icall_sig_double_ptr
, FALSE
);
4778 register_icall (mono_fstore_r4
, mono_icall_sig_void_double_ptr
, FALSE
);
4779 register_icall (mono_fload_r4_arg
, mono_icall_sig_uint32_double
, FALSE
);
4780 register_icall (mono_isfinite_double
, mono_icall_sig_int32_double
, FALSE
);
4783 register_icall (mono_ckfinite
, mono_icall_sig_double_double
, FALSE
);
4785 #ifdef COMPRESSED_INTERFACE_BITMAP
4786 register_icall (mono_class_interface_match
, mono_icall_sig_uint32_ptr_int32
, TRUE
);
4789 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4790 #if SIZEOF_REGISTER == 4
4791 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_uint32_double
, mono_fconv_u4
, TRUE
);
4793 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_ulong_double
, mono_fconv_u8
, TRUE
);
4796 /* other jit icalls */
4797 register_icall (ves_icall_mono_delegate_ctor
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4798 register_icall (ves_icall_mono_delegate_ctor_interp
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4799 register_icall (mono_class_static_field_address
,
4800 mono_icall_sig_ptr_ptr_ptr
, FALSE
);
4801 register_icall (mono_ldtoken_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4802 register_icall (mono_ldtoken_wrapper_generic_shared
,
4803 mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4804 register_icall (mono_get_special_static_data
, mono_icall_sig_ptr_int
, FALSE
);
4805 register_icall (ves_icall_mono_ldstr
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4806 register_icall (mono_helper_stelem_ref_check
, mono_icall_sig_void_object_object
, FALSE
);
4807 register_icall (ves_icall_object_new
, mono_icall_sig_object_ptr_ptr
, FALSE
);
4808 register_icall (ves_icall_object_new_specific
, mono_icall_sig_object_ptr
, FALSE
);
4809 register_icall (ves_icall_array_new
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4810 register_icall (ves_icall_array_new_specific
, mono_icall_sig_object_ptr_int32
, FALSE
);
4811 register_icall (ves_icall_runtime_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4812 register_icall (mono_ldftn
, mono_icall_sig_ptr_ptr
, FALSE
);
4813 register_icall (mono_ldvirtfn
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4814 register_icall (mono_ldvirtfn_gshared
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4815 register_icall (mono_helper_compile_generic_method
, mono_icall_sig_ptr_object_ptr_ptr
, FALSE
);
4816 register_icall (mono_helper_ldstr
, mono_icall_sig_object_ptr_int
, FALSE
);
4817 register_icall (mono_helper_ldstr_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4818 register_icall (mono_helper_newobj_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4819 register_icall (mono_value_copy_internal
, mono_icall_sig_void_ptr_ptr_ptr
, FALSE
);
4820 register_icall (mono_object_castclass_unbox
, mono_icall_sig_object_object_ptr
, FALSE
);
4821 register_icall (mono_break
, NULL
, TRUE
);
4822 register_icall (mono_create_corlib_exception_0
, mono_icall_sig_object_int
, TRUE
);
4823 register_icall (mono_create_corlib_exception_1
, mono_icall_sig_object_int_object
, TRUE
);
4824 register_icall (mono_create_corlib_exception_2
, mono_icall_sig_object_int_object_object
, TRUE
);
4825 register_icall (mono_array_new_1
, mono_icall_sig_object_ptr_int
, FALSE
);
4826 register_icall (mono_array_new_2
, mono_icall_sig_object_ptr_int_int
, FALSE
);
4827 register_icall (mono_array_new_3
, mono_icall_sig_object_ptr_int_int_int
, FALSE
);
4828 register_icall (mono_array_new_4
, mono_icall_sig_object_ptr_int_int_int_int
, FALSE
);
4829 register_icall (mono_array_new_n_icall
, mono_icall_sig_object_ptr_int_ptr
, FALSE
);
4830 register_icall (mono_get_native_calli_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4831 register_icall (mono_resume_unwind
, mono_icall_sig_void_ptr
, TRUE
);
4832 register_icall (mono_gsharedvt_constrained_call
, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr
, FALSE
);
4833 register_icall (mono_gsharedvt_value_copy
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4835 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4836 MonoRangeCopyFunction
const mono_gc_wbarrier_range_copy
= mono_gc_get_range_copy_func ();
4837 register_icall_no_wrapper (mono_gc_wbarrier_range_copy
, mono_icall_sig_void_ptr_ptr_int
);
4839 register_icall (mono_object_castclass_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4840 register_icall (mono_object_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4841 register_icall (mono_generic_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4842 register_icall (mono_fill_class_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4843 register_icall (mono_fill_method_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4845 register_dyn_icall (mini_get_dbg_callbacks ()->user_break
, mono_debugger_agent_user_break
, mono_icall_sig_void
, FALSE
);
4847 register_icall (mini_llvm_init_method
, mono_icall_sig_void_ptr_ptr_ptr_ptr
, TRUE
);
4848 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4849 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4850 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4851 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4852 /* This needs a wrapper so it can have a preserveall cconv */
4853 register_icall (mini_llvmonly_init_vtable_slot
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4854 register_icall (mini_llvmonly_init_delegate
, mono_icall_sig_void_object
, TRUE
);
4855 register_icall (mini_llvmonly_init_delegate_virtual
, mono_icall_sig_void_object_object_ptr
, TRUE
);
4856 register_icall (mini_llvmonly_throw_nullref_exception
, mono_icall_sig_void
, TRUE
);
4857 register_icall (mini_llvmonly_throw_aot_failed_exception
, mono_icall_sig_void_ptr
, TRUE
);
4859 register_icall (mono_get_assembly_object
, mono_icall_sig_object_ptr
, TRUE
);
4860 register_icall (mono_get_method_object
, mono_icall_sig_object_ptr
, TRUE
);
4861 register_icall (mono_throw_method_access
, mono_icall_sig_void_ptr_ptr
, FALSE
);
4862 register_icall (mono_throw_bad_image
, mono_icall_sig_void
, FALSE
);
4863 register_icall_no_wrapper (mono_dummy_jit_icall
, mono_icall_sig_void
);
4865 register_icall_with_wrapper (mono_monitor_enter_internal
, mono_icall_sig_int32_obj
);
4866 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, mono_icall_sig_void_obj_ptr
);
4867 register_icall_no_wrapper (mono_monitor_enter_fast
, mono_icall_sig_int_obj
);
4868 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, mono_icall_sig_int_obj_ptr
);
4871 register_icall (pthread_getspecific
, mono_icall_sig_ptr_ptr
, TRUE
);
4873 /* Register tls icalls */
4874 register_icall_no_wrapper (mono_tls_get_thread_extern
, mono_icall_sig_ptr
);
4875 register_icall_no_wrapper (mono_tls_get_jit_tls_extern
, mono_icall_sig_ptr
);
4876 register_icall_no_wrapper (mono_tls_get_domain_extern
, mono_icall_sig_ptr
);
4877 register_icall_no_wrapper (mono_tls_get_sgen_thread_info_extern
, mono_icall_sig_ptr
);
4878 register_icall_no_wrapper (mono_tls_get_lmf_addr_extern
, mono_icall_sig_ptr
);
4880 register_icall_no_wrapper (mono_interp_entry_from_trampoline
, mono_icall_sig_void_ptr_ptr
);
4881 register_icall_no_wrapper (mono_interp_to_native_trampoline
, mono_icall_sig_void_ptr_ptr
);
4883 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4884 mono_arch_register_icall ();
4888 MonoJitStats mono_jit_stats
= {0};
4891 * Counters of mono_stats and mono_jit_stats can be read without locking during shutdown.
4892 * For all other contexts, assumes that the domain lock is held.
4893 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4895 MONO_NO_SANITIZE_THREAD
4897 mono_runtime_print_stats (void)
4899 if (mono_jit_stats
.enabled
) {
4900 g_print ("Mono Jit statistics\n");
4901 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/ 100.0,
4902 mono_jit_stats
.max_ratio_method
);
4903 g_print ("Biggest method: %" G_GINT32_FORMAT
" (%s)\n", mono_jit_stats
.biggest_method_size
,
4904 mono_jit_stats
.biggest_method
);
4906 g_print ("Delegates created: %" G_GINT32_FORMAT
"\n", mono_stats
.delegate_creations
);
4907 g_print ("Initialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.initialized_class_count
);
4908 g_print ("Used classes: %" G_GINT32_FORMAT
"\n", mono_stats
.used_class_count
);
4909 g_print ("Generic vtables: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_vtable_count
);
4910 g_print ("Methods: %" G_GINT32_FORMAT
"\n", mono_stats
.method_count
);
4911 g_print ("Static data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_static_data_size
);
4912 g_print ("VTable data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_vtable_size
);
4913 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4915 g_print ("\nInitialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_class_count
);
4916 g_print ("Inflated types: %" G_GINT32_FORMAT
"\n", mono_stats
.inflated_type_count
);
4917 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4919 g_print ("Sharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_sharable_methods
);
4920 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_unsharable_methods
);
4921 g_print ("Shared generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_shared_methods
);
4922 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.gsharedvt_methods
);
4924 g_print ("IMT tables size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_tables_size
);
4925 g_print ("IMT number of tables: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_tables
);
4926 g_print ("IMT number of methods: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_methods
);
4927 g_print ("IMT used slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_used_slots
);
4928 g_print ("IMT colliding slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_slots_with_collisions
);
4929 g_print ("IMT max collisions: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_max_collisions_in_slot
);
4930 g_print ("IMT methods at max col: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_method_count_when_max_collisions
);
4931 g_print ("IMT trampolines size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_trampolines_size
);
4933 g_print ("JIT info table inserts: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_insert_count
);
4934 g_print ("JIT info table removes: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_remove_count
);
4935 g_print ("JIT info table lookups: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_lookup_count
);
4937 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, NULL
);
4943 jit_stats_cleanup (void)
4945 g_free (mono_jit_stats
.max_ratio_method
);
4946 mono_jit_stats
.max_ratio_method
= NULL
;
4947 g_free (mono_jit_stats
.biggest_method
);
4948 mono_jit_stats
.biggest_method
= NULL
;
4951 #ifdef DISABLE_CLEANUP
4953 mini_cleanup (MonoDomain
*domain
)
4955 if (mono_stats
.enabled
)
4956 g_printf ("Printing runtime stats at shutdown\n");
4957 mono_runtime_print_stats ();
4958 jit_stats_cleanup ();
4959 mono_jit_dump_cleanup ();
4963 mini_cleanup (MonoDomain
*domain
)
4965 if (mono_stats
.enabled
)
4966 g_printf ("Printing runtime stats at shutdown\n");
4967 if (mono_profiler_sampling_enabled ())
4968 mono_runtime_shutdown_stat_profiler ();
4970 MONO_PROFILER_RAISE (runtime_shutdown_begin
, ());
4973 mono_cominterop_release_all_rcws ();
4976 #ifndef MONO_CROSS_COMPILE
4978 * mono_domain_finalize () needs to be called early since it needs the
4979 * execution engine still fully working (it may invoke managed finalizers).
4981 mono_domain_finalize (domain
, 2000);
4984 /* This accesses metadata so needs to be called before runtime shutdown */
4985 mono_runtime_print_stats ();
4986 jit_stats_cleanup ();
4988 #ifndef MONO_CROSS_COMPILE
4989 mono_runtime_cleanup (domain
);
4992 #ifndef ENABLE_NETCORE
4993 mono_threadpool_cleanup ();
4996 MONO_PROFILER_RAISE (runtime_shutdown_end
, ());
4998 mono_profiler_cleanup ();
5000 if (profile_options
)
5001 g_ptr_array_free (profile_options
, TRUE
);
5003 mono_icall_cleanup ();
5005 mono_runtime_cleanup_handlers ();
5007 #ifndef MONO_CROSS_COMPILE
5008 mono_domain_free (domain
, TRUE
);
5010 free_jit_tls_data (mono_tls_get_jit_tls ());
5014 mono_llvm_cleanup ();
5017 mono_aot_cleanup ();
5019 mono_trampolines_cleanup ();
5021 mono_unwind_cleanup ();
5023 mono_code_manager_destroy (global_codeman
);
5024 g_free (vtable_trampolines
);
5026 mini_jit_cleanup ();
5028 mini_get_interp_callbacks ()->cleanup ();
5030 mono_tramp_info_cleanup ();
5032 mono_arch_cleanup ();
5034 mono_generic_sharing_cleanup ();
5036 mono_cleanup_native_crash_info ();
5040 mono_trace_cleanup ();
5042 if (mono_inject_async_exc_method
)
5043 mono_method_desc_free (mono_inject_async_exc_method
);
5045 mono_tls_free_keys ();
5047 mono_os_mutex_destroy (&jit_mutex
);
5049 mono_code_manager_cleanup ();
5052 mono_w32handle_cleanup ();
5058 mono_set_defaults (int verbose_level
, guint32 opts
)
5060 mini_verbose
= verbose_level
;
5061 mono_set_optimizations (opts
);
5065 mono_disable_optimizations (guint32 opts
)
5067 default_opt
&= ~opts
;
5071 mono_set_optimizations (guint32 opts
)
5074 default_opt_set
= TRUE
;
5075 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
5076 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
5079 mono_set_generic_sharing_vt_supported (TRUE
);
5084 mono_set_verbose_level (guint32 level
)
5086 mini_verbose
= level
;
5090 mono_get_runtime_build_version (void)
5092 return FULL_VERSION
;
5096 * mono_get_runtime_build_info:
5097 * The returned string is owned by the caller. The returned string
5098 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
5099 * \returns the runtime version + build date in string format.
5102 mono_get_runtime_build_info (void)
5104 if (mono_build_date
)
5105 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
5107 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
5111 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
5113 GHashTable
*assemblies
= (GHashTable
*)user_data
;
5114 MonoImage
*image
= mono_assembly_get_image_internal (ass
);
5115 MonoMethod
*method
, *invoke
;
5118 if (g_hash_table_lookup (assemblies
, ass
))
5121 g_hash_table_insert (assemblies
, ass
, ass
);
5123 if (mini_verbose
> 0)
5124 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
5126 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
5129 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, error
);
5131 mono_error_cleanup (error
); /* FIXME don't swallow the error */
5134 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
5136 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
5140 if (mini_verbose
> 1) {
5141 char * desc
= mono_method_full_name (method
, TRUE
);
5142 g_print ("Compiling %d %s\n", count
, desc
);
5145 mono_compile_method_checked (method
, error
);
5146 if (!is_ok (error
)) {
5147 mono_error_cleanup (error
); /* FIXME don't swallow the error */
5150 if (strcmp (method
->name
, "Finalize") == 0) {
5151 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
5152 mono_compile_method_checked (invoke
, error
);
5153 mono_error_assert_ok (error
);
5155 #ifndef DISABLE_REMOTING
5156 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature_internal (method
)->hasthis
) {
5157 invoke
= mono_marshal_get_remoting_invoke_with_check (method
, error
);
5158 mono_error_assert_ok (error
);
5159 mono_compile_method_checked (invoke
, error
);
5160 mono_error_assert_ok (error
);
5165 /* Load and precompile referenced assemblies as well */
5166 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
5167 mono_assembly_load_reference (image
, i
);
5168 if (image
->references
[i
])
5169 mono_precompile_assembly (image
->references
[i
], assemblies
);
5173 void mono_precompile_assemblies ()
5175 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
5177 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
5179 g_hash_table_destroy (assemblies
);
5184 * Have to export this for AOT.
5187 mono_personality (void)
5190 g_assert_not_reached ();
5193 static MonoBreakPolicy
5194 always_insert_breakpoint (MonoMethod
*method
)
5196 return MONO_BREAK_POLICY_ALWAYS
;
5199 static MonoBreakPolicyFunc break_policy_func
= always_insert_breakpoint
;
5202 * mono_set_break_policy:
5203 * \param policy_callback the new callback function
5205 * Allow embedders to decide whether to actually obey breakpoint instructions
5206 * (both break IL instructions and \c Debugger.Break method calls), for example
5207 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5208 * untrusted or semi-trusted code.
5210 * \p policy_callback will be called every time a break point instruction needs to
5211 * be inserted with the method argument being the method that calls \c Debugger.Break
5212 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5213 * if it wants the breakpoint to not be effective in the given method.
5214 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5217 mono_set_break_policy (MonoBreakPolicyFunc policy_callback
)
5219 if (policy_callback
)
5220 break_policy_func
= policy_callback
;
5222 break_policy_func
= always_insert_breakpoint
;
5226 mini_should_insert_breakpoint (MonoMethod
*method
)
5228 switch (break_policy_func (method
)) {
5229 case MONO_BREAK_POLICY_ALWAYS
:
5231 case MONO_BREAK_POLICY_NEVER
:
5233 case MONO_BREAK_POLICY_ON_DBG
:
5234 g_warning ("mdb no longer supported");
5237 g_warning ("Incorrect value returned from break policy callback");
5242 // Custom handlers currently only implemented by Windows.
5245 mono_runtime_install_custom_handlers (const char *handlers
)
5251 mono_runtime_install_custom_handlers_usage (void)
5254 "Custom Handlers:\n"
5255 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5256 " separated list of available handlers to install.\n"
5258 "No handlers supported on current platform.\n");
5260 #endif /* HOST_WIN32 */