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/utils/mono-time.h>
74 #include <mono/metadata/w32handle.h>
75 #include <mono/metadata/threadpool.h>
77 #ifdef ENABLE_PERFTRACING
78 #include <eventpipe/ep.h>
79 #include <eventpipe/ds-server.h>
83 #include "seq-points.h"
89 #include "aot-compiler.h"
90 #include "aot-runtime.h"
91 #include "llvmonly-runtime.h"
93 #include "jit-icalls.h"
96 #include "mini-llvm.h"
97 #include "debugger-agent.h"
99 #include "mini-runtime.h"
100 #include "interp/interp.h"
102 #ifdef MONO_ARCH_LLVM_SUPPORTED
104 #include "mini-llvm-cpp.h"
105 #include "llvm-jit.h"
108 #include "mono/metadata/icall-signatures.h"
109 #include "mono/utils/mono-tls-inline.h"
111 static guint32 default_opt
= 0;
112 static gboolean default_opt_set
= FALSE
;
113 MonoMethodDesc
*mono_stats_method_desc
;
115 gboolean mono_compile_aot
= FALSE
;
116 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
117 gboolean mono_aot_only
= FALSE
;
118 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
119 gboolean mono_llvm_only
= FALSE
;
120 /* By default, don't require AOT but attempt to probe */
121 MonoAotMode mono_aot_mode
= MONO_AOT_MODE_NORMAL
;
122 MonoEEFeatures mono_ee_features
;
124 const char *mono_build_date
;
125 gboolean mono_do_signal_chaining
;
126 gboolean mono_do_crash_chaining
;
127 int mini_verbose
= 0;
130 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
131 * it can load AOT code compiled by LLVM.
133 gboolean mono_use_llvm
= FALSE
;
135 gboolean mono_use_fast_math
= FALSE
;
137 // Lists of allowlisted and blocklisted CPU features
138 MonoCPUFeatures mono_cpu_features_enabled
= (MonoCPUFeatures
)0;
141 MonoCPUFeatures mono_cpu_features_disabled
= MONO_CPU_X86_FULL_SSEAVX_COMBINED
;
143 MonoCPUFeatures mono_cpu_features_disabled
= (MonoCPUFeatures
)0;
146 gboolean mono_use_interpreter
= FALSE
;
147 const char *mono_interp_opts_string
= NULL
;
149 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
150 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
151 static mono_mutex_t jit_mutex
;
153 static MonoCodeManager
*global_codeman
;
155 MonoDebugOptions mini_debug_options
;
158 #ifdef VALGRIND_JIT_REGISTER_MAP
159 int valgrind_register
;
161 GList
* mono_aot_paths
;
163 static GPtrArray
*profile_options
;
165 static GSList
*tramp_infos
;
166 GSList
*mono_interp_only_classes
;
168 static void register_icalls (void);
169 static void runtime_cleanup (MonoDomain
*domain
, gpointer user_data
);
170 #ifdef ENABLE_METADATA_UPDATE
171 static void mini_metadata_update_init (MonoError
*error
);
172 static void mini_invalidate_transformed_interp_methods (MonoDomain
*domain
, MonoAssemblyLoadContext
*alc
, uint32_t generation
);
177 mono_running_on_valgrind (void)
180 if (RUNNING_ON_VALGRIND
){
181 #ifdef VALGRIND_JIT_REGISTER_MAP
182 valgrind_register
= TRUE
;
191 mono_set_use_llvm (mono_bool use_llvm
)
193 mono_use_llvm
= (gboolean
)use_llvm
;
203 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
205 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
208 ud
->method
= (MonoMethod
*)key
;
212 mono_get_method_from_ip_u (void *ip
);
216 mono_get_method_from_ip (void *ip
)
219 MONO_ENTER_GC_UNSAFE
;
220 result
= mono_get_method_from_ip_u (ip
);
227 mono_get_method_from_ip_u (void *ip
)
233 MonoDomain
*domain
= mono_domain_get ();
234 MonoDebugSourceLocation
*location
;
235 FindTrampUserData user_data
;
238 domain
= mono_get_root_domain ();
240 ji
= mono_jit_info_table_find_internal (domain
, ip
, TRUE
, TRUE
);
243 user_data
.method
= NULL
;
244 mono_domain_lock (domain
);
245 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
246 mono_domain_unlock (domain
);
247 if (user_data
.method
) {
248 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
249 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
255 } else if (ji
->is_trampoline
) {
256 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ji
->d
.tramp_info
->name
);
260 method
= jinfo_get_method (ji
);
261 method_name
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_IL
);
262 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
264 char *file_loc
= NULL
;
266 file_loc
= g_strdup_printf ("[%s :: %du]", location
->source_file
, location
->row
);
268 const char *in_interp
= ji
->is_interp
? " interp" : "";
270 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
);
272 mono_debug_free_source_location (location
);
273 g_free (method_name
);
281 * \param ip an instruction pointer address
283 * This method is used from a debugger to get the name of the
284 * method at address \p ip. This routine is typically invoked from
285 * a debugger like this:
287 * (gdb) print mono_pmip ($pc)
289 * \returns the name of the method at address \p ip.
294 return mono_get_method_from_ip (ip
);
298 mono_pmip_u (void *ip
)
300 return mono_get_method_from_ip_u (ip
);
304 * mono_print_method_from_ip:
305 * \param ip an instruction pointer address
307 * This method is used from a debugger to get the name of the
308 * method at address \p ip.
310 * This prints the name of the method at address \p ip in the standard
311 * output. Unlike \c mono_pmip which returns a string, this routine
312 * prints the value on the standard output.
315 mono_print_method_from_ip (void *ip
)
319 MonoDebugSourceLocation
*source
;
320 MonoDomain
*domain
= mono_domain_get ();
321 MonoDomain
*target_domain
= mono_domain_get ();
322 FindTrampUserData user_data
;
323 MonoGenericSharingContext
*gsctx
;
324 const char *shared_type
;
327 domain
= mono_get_root_domain ();
328 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
329 if (ji
&& ji
->is_trampoline
) {
330 MonoTrampInfo
*tinfo
= ji
->d
.tramp_info
;
332 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
338 user_data
.method
= NULL
;
339 mono_domain_lock (domain
);
340 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
341 mono_domain_unlock (domain
);
343 if (user_data
.method
) {
344 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
345 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
350 g_print ("No method at %p\n", ip
);
354 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
355 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
357 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
360 if (gsctx
->is_gsharedvt
)
361 shared_type
= "gsharedvt ";
363 shared_type
= "gshared ";
366 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
);
369 g_print ("%s:%d\n", source
->source_file
, source
->row
);
372 mono_debug_free_source_location (source
);
377 * mono_method_same_domain:
379 * Determine whenever two compiled methods are in the same domain, thus
380 * the address of the callee can be embedded in the caller.
382 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
384 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
388 * If the call was made from domain-neutral to domain-specific
389 * code, we can't patch the call site.
391 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
396 cmethod
= jinfo_get_method (caller
);
397 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
398 (strstr (cmethod
->name
, "InvokeInDomain"))) {
399 /* The InvokeInDomain methods change the current appdomain */
406 * mono_global_codeman_reserve:
408 * Allocate code memory from the global code manager.
410 void *(mono_global_codeman_reserve
) (int size
)
415 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
417 if (!global_codeman
) {
418 /* This can happen during startup */
419 global_codeman
= mono_code_manager_new ();
420 return mono_code_manager_reserve (global_codeman
, size
);
424 ptr
= mono_code_manager_reserve (global_codeman
, size
);
430 /* The callback shouldn't take any locks */
432 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
435 mono_code_manager_foreach (global_codeman
, func
, user_data
);
440 * mono_create_unwind_op:
442 * Create an unwind op with the given parameters.
445 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
447 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
458 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
460 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
463 res
->has_context
= context
!= NULL
;
465 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
471 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
473 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
477 * mono_tramp_info_create:
479 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
480 * of JI, and UNWIND_OPS.
483 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
485 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
487 info
->name
= g_strdup (name
);
489 info
->code_size
= code_size
;
491 info
->unwind_ops
= unwind_ops
;
497 mono_tramp_info_free (MonoTrampInfo
*info
)
502 mono_free_unwind_info (info
->unwind_ops
);
503 if (info
->owns_uw_info
)
504 g_free (info
->uw_info
);
509 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
513 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
514 mono_jit_info_init (ji
, NULL
, (guint8
*)MINI_FTNPTR_TO_ADDR (info
->code
), info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
515 ji
->d
.tramp_info
= info
;
516 ji
->is_trampoline
= TRUE
;
518 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
520 mono_jit_info_table_add (domain
, ji
);
524 * mono_tramp_info_register:
526 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
531 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
539 domain
= mono_get_root_domain ();
542 copy
= mono_domain_alloc0 (domain
, sizeof (MonoTrampInfo
));
544 copy
= g_new0 (MonoTrampInfo
, 1);
546 copy
->code
= info
->code
;
547 copy
->code_size
= info
->code_size
;
548 copy
->name
= g_strdup (info
->name
);
549 copy
->method
= info
->method
;
551 if (info
->unwind_ops
) {
552 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
553 copy
->owns_uw_info
= TRUE
;
555 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
556 guint8
*temp
= copy
->uw_info
;
557 copy
->uw_info
= mono_domain_alloc (domain
, copy
->uw_info_len
);
558 memcpy (copy
->uw_info
, temp
, copy
->uw_info_len
);
562 /* Trampolines from aot have the unwind ops already encoded */
563 copy
->uw_info
= info
->uw_info
;
564 copy
->uw_info_len
= info
->uw_info_len
;
567 mono_save_trampoline_xdebug_info (info
);
568 mono_lldb_save_trampoline_info (info
);
570 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
572 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
576 /* If no root domain has been created yet, postpone the registration. */
578 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
580 } else if (copy
->uw_info
|| info
->method
) {
581 /* Only register trampolines that have unwind info */
582 register_trampoline_jit_info (domain
, copy
);
585 if (mono_jit_map_is_enabled ())
586 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
588 mono_tramp_info_free (info
);
592 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
594 mono_tramp_info_register_internal (info
, domain
, FALSE
);
598 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
600 mono_tramp_info_register_internal (info
, domain
, TRUE
);
604 mono_tramp_info_cleanup (void)
608 for (l
= tramp_infos
; l
; l
= l
->next
) {
609 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
611 mono_tramp_info_free (info
);
613 g_slist_free (tramp_infos
);
616 /* Register trampolines created before the root domain was created in the jit info tables */
618 register_trampolines (MonoDomain
*domain
)
622 for (l
= tramp_infos
; l
; l
= l
->next
) {
623 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
625 register_trampoline_jit_info (domain
, info
);
629 G_GNUC_UNUSED
static void
635 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
636 * Set a breakpoint in break_count () to break the last time <x> is done.
638 G_GNUC_UNUSED gboolean
639 mono_debug_count (void)
641 static int count
= 0, int_val
= 0;
642 static gboolean inited
, has_value
= FALSE
;
647 char *value
= g_getenv ("COUNT");
649 int_val
= atoi (value
);
659 if (count
== int_val
)
669 mono_icall_get_wrapper_method (MonoJitICallInfo
* callinfo
)
671 /* This icall is used to check for exceptions, so don't check in the wrapper */
672 gboolean check_exc
= (callinfo
!= &mono_get_jit_icall_info ()->mono_thread_interruption_checkpoint
);
674 return mono_marshal_get_icall_wrapper (callinfo
, check_exc
);
678 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
682 gconstpointer addr
, trampoline
;
683 MonoDomain
*domain
= mono_get_root_domain ();
685 if (callinfo
->wrapper
)
686 return callinfo
->wrapper
;
688 wrapper
= mono_icall_get_wrapper_method (callinfo
);
691 addr
= mono_compile_method_checked (wrapper
, error
);
692 mono_error_assert_ok (error
);
693 mono_memory_barrier ();
694 callinfo
->wrapper
= addr
;
697 if (callinfo
->trampoline
)
698 return callinfo
->trampoline
;
699 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, error
);
700 mono_error_assert_ok (error
);
701 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
704 if (!callinfo
->trampoline
) {
705 callinfo
->trampoline
= trampoline
;
707 mono_loader_unlock ();
709 return callinfo
->trampoline
;
714 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
716 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
719 static MonoJitDynamicMethodInfo
*
720 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
722 MonoJitDynamicMethodInfo
*res
;
724 if (domain_jit_info (domain
)->dynamic_code_hash
)
725 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
732 template <typename T
>
734 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, T func
, const char *symbol
, gboolean no_wrapper
)
737 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, gpointer func
, const char *symbol
, gboolean no_wrapper
)
741 mini_register_opcode_emulation (opcode
, jit_icall_info
, name
, sig
, func
, symbol
, no_wrapper
);
743 // FIXME ifdef in mini_register_opcode_emulation and just call it.
745 g_assert (!sig
->hasthis
);
746 g_assert (sig
->param_count
< 3);
748 mono_register_jit_icall_info (jit_icall_info
, func
, name
, sig
, no_wrapper
, symbol
);
752 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
753 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
756 * For JIT icalls implemented in C.
757 * NAME should be the same as the name of the C function whose address is FUNC.
758 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
759 * can't throw exceptions.
761 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
762 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
764 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
765 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
766 * must be extern "C".
768 #define register_icall(func, sig, avoid_wrapper) \
769 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
771 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
772 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
775 * Register an icall where FUNC is dynamically generated or otherwise not
776 * possible to link to it using NAME during AOT.
778 * func is an expression, such a local variable or a function call to get a function pointer.
779 * name is an identifier
781 * Providing func and name separately is what distinguishes "dyn" from regular.
783 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
785 #define register_dyn_icall(func, name, sig, save) \
786 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
791 MonoJitTlsData
*jit_tls
;
793 if ((jit_tls
= mono_tls_get_jit_tls ()))
796 * We do not assert here because this function can be called from
797 * mini-gc.c on a thread that has not executed any managed code, yet
798 * (the thread object allocation can trigger a collection).
804 mono_set_lmf (MonoLMF
*lmf
)
806 (*mono_get_lmf_addr ()) = lmf
;
810 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
812 MonoThreadInfo
*info
;
814 mono_tls_set_jit_tls (jit_tls
);
816 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
817 info
= mono_thread_info_current ();
819 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
823 mono_set_lmf_addr (MonoLMF
**lmf_addr
)
825 MonoThreadInfo
*info
;
827 mono_tls_set_lmf_addr (lmf_addr
);
829 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
830 info
= mono_thread_info_current ();
832 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
838 * Push an MonoLMFExt frame on the LMF stack.
841 mono_push_lmf (MonoLMFExt
*ext
)
845 lmf_addr
= mono_get_lmf_addr ();
847 ext
->lmf
.previous_lmf
= *lmf_addr
;
848 /* Mark that this is a MonoLMFExt */
849 ext
->lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
->lmf
.previous_lmf
) | 2);
851 mono_set_lmf ((MonoLMF
*)ext
);
857 * Pop the last frame from the LMF stack.
860 mono_pop_lmf (MonoLMF
*lmf
)
862 mono_set_lmf ((MonoLMF
*)(((gssize
)lmf
->previous_lmf
) & ~3));
866 * mono_jit_thread_attach:
868 * Called by Xamarin.Mac and other products. Attach thread to runtime if
869 * needed and switch to @domain.
871 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
873 * If the thread is newly-attached, put into GC Safe mode.
875 * @return the original domain which needs to be restored, or NULL.
878 mono_jit_thread_attach (MonoDomain
*domain
)
884 /* Happens when called from AOTed code which is only used in the root domain. */
885 domain
= mono_get_root_domain ();
890 attached
= mono_tls_get_jit_tls () != NULL
;
894 gboolean background
= TRUE
;
895 mono_thread_attach_external_native_thread (domain
, background
);
897 /* mono_jit_thread_attach is external-only and not called by
898 * the runtime on any of our own threads. So if we get here,
899 * the thread is running native code - leave it in GC Safe mode
900 * and leave it to the n2m invoke wrappers or MONO_API entry
901 * points to switch to GC Unsafe.
903 MONO_STACKDATA (stackdata
);
904 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata
);
907 orig
= mono_domain_get ();
909 mono_domain_set_fast (domain
, TRUE
);
911 return orig
!= domain
? orig
: NULL
;
915 * mono_jit_set_domain:
917 * Set domain to @domain if @domain is not null
920 mono_jit_set_domain (MonoDomain
*domain
)
922 g_assert (!mono_threads_is_blocking_transition_enabled ());
925 mono_domain_set_fast (domain
, TRUE
);
930 * \param obj exception object
931 * Abort the thread, print exception information and stack trace
934 mono_thread_abort (MonoObject
*obj
)
936 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
938 /* handle_remove should be eventually called for this thread, too
941 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
942 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
) ||
943 ((obj
->vtable
->klass
) == mono_class_try_get_appdomain_unloaded_exception_class () &&
944 mono_thread_info_current ()->runtime_thread
)) {
947 mono_invoke_unhandled_exception_hook (obj
);
951 static MonoJitTlsData
*
952 setup_jit_tls_data (gpointer stack_start
, MonoAbortFunction abort_func
)
954 MonoJitTlsData
*jit_tls
;
957 jit_tls
= mono_tls_get_jit_tls ();
961 jit_tls
= g_new0 (MonoJitTlsData
, 1);
963 jit_tls
->abort_func
= abort_func
;
964 jit_tls
->end_of_stack
= stack_start
;
966 mono_set_jit_tls (jit_tls
);
968 lmf
= g_new0 (MonoLMF
, 1);
969 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
971 jit_tls
->first_lmf
= lmf
;
973 mono_set_lmf_addr (&jit_tls
->lmf
);
977 #ifdef MONO_ARCH_HAVE_TLS_INIT
978 mono_arch_tls_init ();
981 mono_setup_altstack (jit_tls
);
987 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
989 //This happens during AOT cuz the thread is never attached
992 mono_free_altstack (jit_tls
);
994 if (jit_tls
->interp_context
)
995 mini_get_interp_callbacks ()->free_context (jit_tls
->interp_context
);
997 g_free (jit_tls
->first_lmf
);
1002 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
1004 MonoThreadInfo
*thread
;
1005 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
1006 thread
= mono_thread_info_current_unchecked ();
1008 thread
->jit_data
= jit_tls
;
1010 mono_arch_cpu_init ();
1013 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
1016 mono_thread_abort_dummy (MonoObject
*obj
)
1018 if (mono_thread_attach_aborted_cb
)
1019 mono_thread_attach_aborted_cb (obj
);
1021 mono_thread_abort (obj
);
1025 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
1027 MonoThreadInfo
*thread
;
1028 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
1029 thread
= mono_thread_info_current_unchecked ();
1031 thread
->jit_data
= jit_tls
;
1033 mono_arch_cpu_init ();
1037 mini_thread_cleanup (MonoNativeThreadId tid
)
1039 MonoJitTlsData
*jit_tls
= NULL
;
1040 MonoThreadInfo
*info
;
1042 info
= mono_thread_info_current_unchecked ();
1044 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1045 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1046 * not a trivial thing.
1048 * The current offender is mono_thread_manage which cleanup threads from the outside.
1050 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
1051 jit_tls
= info
->jit_data
;
1052 info
->jit_data
= NULL
;
1054 mono_set_jit_tls (NULL
);
1056 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1057 if (mono_get_lmf ()) {
1058 mono_set_lmf (NULL
);
1059 mono_set_lmf_addr (NULL
);
1062 info
= mono_thread_info_lookup (tid
);
1064 jit_tls
= info
->jit_data
;
1065 info
->jit_data
= NULL
;
1067 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1071 free_jit_tls_data (jit_tls
);
1075 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
1077 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
1081 ji
->data
.target
= target
;
1087 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1089 static const char* const patch_info_str
[] = {
1090 #define PATCH_INFO(a,b) "" #a,
1091 #include "patch-info.h"
1096 mono_ji_type_to_string (MonoJumpInfoType type
)
1098 return patch_info_str
[type
];
1102 mono_print_ji (const MonoJumpInfo
*ji
)
1104 const char *type
= patch_info_str
[ji
->type
];
1106 case MONO_PATCH_INFO_RGCTX_FETCH
:
1107 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1108 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1110 printf ("[%s ", type
);
1111 mono_print_ji (entry
->data
);
1112 printf (" -> %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1115 case MONO_PATCH_INFO_METHOD
:
1116 case MONO_PATCH_INFO_METHODCONST
:
1117 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1118 char *s
= mono_method_get_full_name (ji
->data
.method
);
1119 printf ("[%s %s]", type
, s
);
1123 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1124 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji
->data
.jit_icall_id
)->name
);
1126 case MONO_PATCH_INFO_CLASS
:
1127 case MONO_PATCH_INFO_VTABLE
: {
1128 char *name
= mono_class_full_name (ji
->data
.klass
);
1129 printf ("[%s %s]", type
, name
);
1134 printf ("[%s]", type
);
1142 mono_ji_type_to_string (MonoJumpInfoType type
)
1148 mono_print_ji (const MonoJumpInfo
*ji
)
1155 * mono_patch_info_dup_mp:
1157 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1160 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1162 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1163 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1165 switch (patch_info
->type
) {
1166 case MONO_PATCH_INFO_RVA
:
1167 case MONO_PATCH_INFO_LDSTR
:
1168 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1169 case MONO_PATCH_INFO_LDTOKEN
:
1170 case MONO_PATCH_INFO_DECLSEC
:
1171 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1172 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1174 case MONO_PATCH_INFO_SWITCH
:
1175 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1176 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1177 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1178 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1180 case MONO_PATCH_INFO_RGCTX_FETCH
:
1181 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1182 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1183 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1184 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1186 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1187 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1188 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1190 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1191 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1192 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1194 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1195 MonoGSharedVtMethodInfo
*info
;
1196 MonoGSharedVtMethodInfo
*oinfo
;
1199 oinfo
= patch_info
->data
.gsharedvt_method
;
1200 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1201 res
->data
.gsharedvt_method
= info
;
1202 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1203 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1204 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1205 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1206 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1208 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1210 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1211 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1214 case MONO_PATCH_INFO_VIRT_METHOD
: {
1215 MonoJumpInfoVirtMethod
*info
;
1216 MonoJumpInfoVirtMethod
*oinfo
;
1218 oinfo
= patch_info
->data
.virt_method
;
1219 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1220 res
->data
.virt_method
= info
;
1221 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1232 mono_patch_info_hash (gconstpointer data
)
1234 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1235 const MonoJumpInfoType type
= ji
->type
;
1236 guint hash
= type
<< 8;
1239 case MONO_PATCH_INFO_RVA
:
1240 case MONO_PATCH_INFO_LDSTR
:
1241 case MONO_PATCH_INFO_LDTOKEN
:
1242 case MONO_PATCH_INFO_DECLSEC
:
1243 return hash
| ji
->data
.token
->token
;
1244 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1245 return hash
| ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1246 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: // Hash on the selector name
1247 case MONO_PATCH_INFO_LDSTR_LIT
:
1248 return g_str_hash (ji
->data
.name
);
1249 case MONO_PATCH_INFO_VTABLE
:
1250 case MONO_PATCH_INFO_CLASS
:
1251 case MONO_PATCH_INFO_IID
:
1252 case MONO_PATCH_INFO_ADJUSTED_IID
:
1253 case MONO_PATCH_INFO_METHODCONST
:
1254 case MONO_PATCH_INFO_METHOD
:
1255 case MONO_PATCH_INFO_METHOD_JUMP
:
1256 case MONO_PATCH_INFO_METHOD_FTNDESC
:
1257 case MONO_PATCH_INFO_IMAGE
:
1258 case MONO_PATCH_INFO_ICALL_ADDR
:
1259 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1260 case MONO_PATCH_INFO_FIELD
:
1261 case MONO_PATCH_INFO_SFLDA
:
1262 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1263 case MONO_PATCH_INFO_METHOD_RGCTX
:
1264 case MONO_PATCH_INFO_SIGNATURE
:
1265 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1266 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1267 case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE
:
1268 return hash
| (gssize
)ji
->data
.target
;
1269 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1270 return hash
| (gssize
)ji
->data
.gsharedvt
->method
;
1271 case MONO_PATCH_INFO_RGCTX_FETCH
:
1272 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1273 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1274 hash
|= e
->in_mrgctx
| e
->info_type
| mono_patch_info_hash (e
->data
);
1276 return hash
| (gssize
)e
->d
.method
;
1278 return hash
| (gssize
)e
->d
.klass
;
1280 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1281 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1282 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1283 case MONO_PATCH_INFO_GC_NURSERY_START
:
1284 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1285 case MONO_PATCH_INFO_GOT_OFFSET
:
1286 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1287 case MONO_PATCH_INFO_AOT_MODULE
:
1288 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
:
1289 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
:
1290 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES
:
1291 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE
:
1293 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1294 return hash
| ji
->data
.uindex
;
1295 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1296 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1297 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1298 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1299 return hash
| ji
->data
.index
;
1300 case MONO_PATCH_INFO_SWITCH
:
1301 return hash
| ji
->data
.table
->table_size
;
1302 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1303 return hash
| (gssize
)ji
->data
.gsharedvt_method
->method
;
1304 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1305 return hash
| (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1306 case MONO_PATCH_INFO_VIRT_METHOD
: {
1307 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1309 return hash
| (gssize
)info
->klass
| (gssize
)info
->method
;
1311 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1312 return hash
| mono_signature_hash (ji
->data
.sig
);
1313 case MONO_PATCH_INFO_R8_GOT
:
1314 return hash
| (guint32
)*(double*)ji
->data
.target
;
1315 case MONO_PATCH_INFO_R4_GOT
:
1316 return hash
| (guint32
)*(float*)ji
->data
.target
;
1318 printf ("info type: %d\n", ji
->type
);
1319 mono_print_ji (ji
); printf ("\n");
1320 g_assert_not_reached ();
1321 case MONO_PATCH_INFO_NONE
:
1327 * mono_patch_info_equal:
1329 * This might fail to recognize equivalent patches, i.e. floats, so its only
1330 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1334 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1336 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1337 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1339 MonoJumpInfoType
const ji1_type
= ji1
->type
;
1340 MonoJumpInfoType
const ji2_type
= ji2
->type
;
1342 if (ji1_type
!= ji2_type
)
1346 case MONO_PATCH_INFO_RVA
:
1347 case MONO_PATCH_INFO_LDSTR
:
1348 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1349 case MONO_PATCH_INFO_LDTOKEN
:
1350 case MONO_PATCH_INFO_DECLSEC
:
1351 return ji1
->data
.token
->image
== ji2
->data
.token
->image
&&
1352 ji1
->data
.token
->token
== ji2
->data
.token
->token
&&
1353 ji1
->data
.token
->has_context
== ji2
->data
.token
->has_context
&&
1354 ji1
->data
.token
->context
.class_inst
== ji2
->data
.token
->context
.class_inst
&&
1355 ji1
->data
.token
->context
.method_inst
== ji2
->data
.token
->context
.method_inst
;
1356 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1357 case MONO_PATCH_INFO_LDSTR_LIT
:
1358 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1359 case MONO_PATCH_INFO_RGCTX_FETCH
:
1360 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1361 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1362 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1364 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
);
1366 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1367 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1368 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1370 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1372 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1373 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1374 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1375 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
;
1376 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1377 return ji1
->data
.uindex
== ji2
->data
.uindex
;
1378 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1379 return ji1
->data
.index
== ji2
->data
.index
;
1380 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1381 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1382 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1383 return ji1
->data
.jit_icall_id
== ji2
->data
.jit_icall_id
;
1384 case MONO_PATCH_INFO_VIRT_METHOD
:
1385 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1386 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1387 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
);
1388 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1389 case MONO_PATCH_INFO_NONE
:
1395 return ji1
->data
.target
== ji2
->data
.target
;
1399 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1401 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1402 gconstpointer target
= NULL
;
1406 switch (patch_info
->type
) {
1407 case MONO_PATCH_INFO_BB
:
1409 * FIXME: This could be hit for methods without a prolog. Should use -1
1410 * but too much code depends on a 0 initial value.
1412 //g_assert (patch_info->data.bb->native_offset);
1413 target
= patch_info
->data
.bb
->native_offset
+ code
;
1415 case MONO_PATCH_INFO_ABS
:
1416 target
= patch_info
->data
.target
;
1418 case MONO_PATCH_INFO_LABEL
:
1419 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1421 case MONO_PATCH_INFO_IP
:
1424 case MONO_PATCH_INFO_JIT_ICALL_ID
: {
1425 MonoJitICallInfo
* const mi
= mono_find_jit_icall_info (patch_info
->data
.jit_icall_id
);
1426 target
= mono_icall_get_wrapper (mi
);
1429 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1430 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
: {
1431 MonoJitICallInfo
* const mi
= mono_find_jit_icall_info (patch_info
->data
.jit_icall_id
);
1435 case MONO_PATCH_INFO_METHOD_JUMP
:
1436 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1440 case MONO_PATCH_INFO_METHOD
:
1441 if (patch_info
->data
.method
== method
) {
1444 /* get the trampoline to the method from the domain */
1445 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1450 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1452 * Return an ftndesc for either AOTed code, or for an interp entry.
1454 target
= mini_llvmonly_load_method_ftndesc (patch_info
->data
.method
, FALSE
, FALSE
, error
);
1455 return_val_if_nok (error
, NULL
);
1458 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1461 mono_domain_lock (domain
);
1462 if (!domain_jit_info (domain
)->method_code_hash
)
1463 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1464 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1466 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1467 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1469 mono_domain_unlock (domain
);
1473 case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE
: {
1474 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1477 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1478 target
= (gpointer
)&mono_polling_required
;
1480 case MONO_PATCH_INFO_SWITCH
: {
1481 #ifndef MONO_ARCH_NO_CODEMAN
1482 gpointer
*jump_table
;
1485 if (method
&& method
->dynamic
) {
1486 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1488 MonoMemoryManager
*mem_manager
= m_method_get_mem_manager (domain
, method
);
1489 if (mono_aot_only
) {
1490 jump_table
= (void **)mono_mem_manager_alloc (mem_manager
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1492 jump_table
= (void **)mono_mem_manager_code_reserve (mem_manager
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1496 mono_codeman_enable_write ();
1497 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1498 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1500 mono_codeman_disable_write ();
1502 target
= jump_table
;
1504 g_assert_not_reached ();
1509 case MONO_PATCH_INFO_METHODCONST
:
1510 case MONO_PATCH_INFO_CLASS
:
1511 case MONO_PATCH_INFO_IMAGE
:
1512 case MONO_PATCH_INFO_FIELD
:
1513 case MONO_PATCH_INFO_SIGNATURE
:
1514 case MONO_PATCH_INFO_AOT_MODULE
:
1515 target
= patch_info
->data
.target
;
1517 case MONO_PATCH_INFO_IID
:
1518 mono_class_init_internal (patch_info
->data
.klass
);
1519 target
= GUINT_TO_POINTER (m_class_get_interface_id (patch_info
->data
.klass
));
1521 case MONO_PATCH_INFO_ADJUSTED_IID
:
1522 mono_class_init_internal (patch_info
->data
.klass
);
1523 target
= GUINT_TO_POINTER ((guint32
)(-((m_class_get_interface_id (patch_info
->data
.klass
) + 1) * TARGET_SIZEOF_VOID_P
)));
1525 case MONO_PATCH_INFO_VTABLE
:
1526 target
= mono_class_vtable_checked (domain
, patch_info
->data
.klass
, error
);
1527 mono_error_assert_ok (error
);
1529 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1530 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1532 if (del_tramp
->is_virtual
)
1533 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1535 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1538 case MONO_PATCH_INFO_SFLDA
: {
1539 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, patch_info
->data
.field
->parent
, error
);
1540 mono_error_assert_ok (error
);
1542 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1543 gpointer addr
= NULL
;
1545 mono_domain_lock (domain
);
1546 if (domain
->special_static_fields
)
1547 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1548 mono_domain_unlock (domain
);
1553 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (!method
|| mono_class_needs_cctor_run (vtable
->klass
, method
)))
1554 /* Done by the generated code */
1558 if (!mono_runtime_class_init_full (vtable
, error
)) {
1563 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1566 case MONO_PATCH_INFO_RVA
: {
1567 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1570 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1571 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1574 case MONO_PATCH_INFO_R4
:
1575 case MONO_PATCH_INFO_R4_GOT
:
1576 case MONO_PATCH_INFO_R8
:
1577 case MONO_PATCH_INFO_R8_GOT
:
1578 target
= patch_info
->data
.target
;
1580 case MONO_PATCH_INFO_EXC_NAME
:
1581 target
= patch_info
->data
.name
;
1583 case MONO_PATCH_INFO_LDSTR
:
1585 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1586 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1588 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1590 MonoClass
*handle_class
;
1592 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1593 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1596 mono_class_init_internal (handle_class
);
1597 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType
*)handle
));
1599 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1604 case MONO_PATCH_INFO_LDTOKEN
: {
1606 MonoClass
*handle_class
;
1608 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1609 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1610 mono_error_assert_msg_ok (error
, "Could not patch ldtoken");
1611 mono_class_init_internal (handle_class
);
1616 case MONO_PATCH_INFO_DECLSEC
:
1617 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1619 case MONO_PATCH_INFO_ICALL_ADDR
:
1620 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1621 /* run_cctors == 0 -> AOT */
1622 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1624 target
= mono_lookup_pinvoke_call_internal (patch_info
->data
.method
, error
);
1628 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
));
1634 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1636 if (mono_is_missing_icall_addr (target
) && run_cctors
)
1637 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1640 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1641 target
= &mono_thread_interruption_request_flag
;
1643 case MONO_PATCH_INFO_METHOD_RGCTX
:
1644 target
= mini_method_get_rgctx (patch_info
->data
.method
);
1646 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1647 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1649 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1652 case MONO_PATCH_INFO_BB_OVF
:
1653 case MONO_PATCH_INFO_EXC_OVF
:
1654 case MONO_PATCH_INFO_GOT_OFFSET
:
1655 case MONO_PATCH_INFO_NONE
:
1657 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1658 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1660 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1663 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1664 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1666 /* AOT, not needed */
1669 target
= mono_arch_get_seq_point_info (domain
, code
);
1672 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1673 int card_table_shift_bits
;
1674 gpointer card_table_mask
;
1676 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1679 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1683 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1686 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1690 mono_gc_get_nursery (&shift_bits
, &size
);
1692 target
= (gpointer
)(gssize
)shift_bits
;
1695 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1696 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1699 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1703 case MONO_PATCH_INFO_LDSTR_LIT
: {
1707 len
= strlen ((const char *)patch_info
->data
.target
);
1708 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1709 memcpy (s
, patch_info
->data
.target
, len
);
1714 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1715 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1717 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
: {
1718 target
= (gpointer
) &mono_profiler_state
.gc_allocation_count
;
1721 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
: {
1722 target
= (gpointer
) &mono_profiler_state
.exception_clause_count
;
1725 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES
:
1726 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE
: {
1727 /* Resolved in aot-runtime.c */
1728 g_assert_not_reached ();
1733 g_assert_not_reached ();
1736 return (gpointer
)target
;
1740 * mini_register_jump_site:
1742 * Register IP as a jump/tailcall site which calls METHOD.
1743 * This is needed because common_call_trampoline () cannot patch
1744 * the call site because the caller ip is not available for jumps.
1747 mini_register_jump_site (MonoDomain
*domain
, MonoMethod
*method
, gpointer ip
)
1749 MonoJumpList
*jlist
;
1751 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1752 method
= shared_method
? shared_method
: method
;
1754 mono_domain_lock (domain
);
1755 jlist
= (MonoJumpList
*)g_hash_table_lookup (domain_jit_info (domain
)->jump_target_hash
, method
);
1757 jlist
= (MonoJumpList
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpList
));
1758 g_hash_table_insert (domain_jit_info (domain
)->jump_target_hash
, method
, jlist
);
1760 jlist
->list
= g_slist_prepend (jlist
->list
, ip
);
1761 mono_domain_unlock (domain
);
1765 * mini_patch_jump_sites:
1767 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1770 mini_patch_jump_sites (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1772 GHashTable
*hash
= domain_jit_info (domain
)->jump_target_hash
;
1777 MonoJumpInfo patch_info
;
1778 MonoJumpList
*jlist
;
1781 /* The caller/callee might use different instantiations */
1782 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1783 method
= shared_method
? shared_method
: method
;
1785 mono_domain_lock (domain
);
1786 jlist
= (MonoJumpList
*)g_hash_table_lookup (hash
, method
);
1788 g_hash_table_remove (hash
, method
);
1789 mono_domain_unlock (domain
);
1791 patch_info
.next
= NULL
;
1792 patch_info
.ip
.i
= 0;
1793 patch_info
.type
= MONO_PATCH_INFO_METHOD_JUMP
;
1794 patch_info
.data
.method
= method
;
1796 mono_codeman_enable_write ();
1798 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1799 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
)
1800 mono_arch_patch_code_new (NULL
, domain
, (guint8
*)tmp
->data
, &patch_info
, addr
);
1802 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1803 // for gshared methods
1804 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
1806 mono_arch_patch_code (NULL
, NULL
, domain
, tmp
->data
, &patch_info
, TRUE
, error
);
1807 mono_error_assert_ok (error
);
1811 mono_codeman_disable_write ();
1816 * mini_patch_llvm_jit_callees:
1818 * Patch function address slots used by llvm JITed code.
1821 mini_patch_llvm_jit_callees (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1823 if (!domain_jit_info (domain
)->llvm_jit_callees
)
1825 GSList
*callees
= (GSList
*)g_hash_table_lookup (domain_jit_info (domain
)->llvm_jit_callees
, method
);
1828 for (l
= callees
; l
; l
= l
->next
) {
1829 gpointer
*slot
= (gpointer
*)l
->data
;
1836 mini_init_gsctx (MonoDomain
*domain
, MonoMemPool
*mp
, MonoGenericContext
*context
, MonoGenericSharingContext
*gsctx
)
1838 MonoGenericInst
*inst
;
1841 memset (gsctx
, 0, sizeof (MonoGenericSharingContext
));
1843 if (context
&& context
->class_inst
) {
1844 inst
= context
->class_inst
;
1845 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1846 MonoType
*type
= inst
->type_argv
[i
];
1848 if (mini_is_gsharedvt_gparam (type
))
1849 gsctx
->is_gsharedvt
= TRUE
;
1852 if (context
&& context
->method_inst
) {
1853 inst
= context
->method_inst
;
1855 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1856 MonoType
*type
= inst
->type_argv
[i
];
1858 if (mini_is_gsharedvt_gparam (type
))
1859 gsctx
->is_gsharedvt
= TRUE
;
1865 * LOCKING: Acquires the jit code hash lock.
1868 mini_lookup_method (MonoDomain
*domain
, MonoMethod
*method
, MonoMethod
*shared
)
1871 static gboolean inited
= FALSE
;
1872 static int lookups
= 0;
1873 static int failed_lookups
= 0;
1875 mono_domain_jit_code_hash_lock (domain
);
1876 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
1877 if (!ji
&& shared
) {
1878 /* Try generic sharing */
1879 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, shared
);
1880 if (ji
&& !ji
->has_generic_jit_info
)
1883 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &lookups
);
1884 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &failed_lookups
);
1892 mono_domain_jit_code_hash_unlock (domain
);
1898 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
1904 ji
= mini_lookup_method (domain
, method
, NULL
);
1907 if (!mono_method_is_generic_sharable (method
, FALSE
))
1909 shared
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
1910 mono_error_assert_ok (error
);
1911 ji
= mini_lookup_method (domain
, method
, shared
);
1918 mini_get_class (MonoMethod
*method
, guint32 token
, MonoGenericContext
*context
)
1923 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1924 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
1926 klass
= mono_class_inflate_generic_class_checked (klass
, context
, error
);
1927 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1930 klass
= mono_class_get_and_inflate_typespec_checked (m_class_get_image (method
->klass
), token
, context
, error
);
1931 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1934 mono_class_init_internal (klass
);
1939 static FILE* perf_map_file
;
1942 mono_enable_jit_map (void)
1944 if (!perf_map_file
) {
1946 g_snprintf (name
, sizeof (name
), "/tmp/perf-%d.map", getpid ());
1948 perf_map_file
= fopen (name
, "w");
1953 mono_emit_jit_tramp (void *start
, int size
, const char *desc
)
1956 fprintf (perf_map_file
, "%" PRIx64
" %x %s\n", (guint64
)(gsize
)start
, size
, desc
);
1960 mono_emit_jit_map (MonoJitInfo
*jinfo
)
1962 if (perf_map_file
) {
1963 char *name
= mono_method_full_name (jinfo_get_method (jinfo
), TRUE
);
1964 mono_emit_jit_tramp (jinfo
->code_start
, jinfo
->code_size
, name
);
1970 mono_jit_map_is_enabled (void)
1972 return perf_map_file
!= NULL
;
1977 #ifdef ENABLE_JIT_DUMP
1978 #include <sys/mman.h>
1979 #include <sys/syscall.h>
1982 static FILE *perf_dump_file
;
1983 static mono_mutex_t perf_dump_mutex
;
1984 static void *perf_dump_mmap_addr
= MAP_FAILED
;
1985 static guint32 perf_dump_pid
;
1986 static clockid_t clock_id
= CLOCK_MONOTONIC
;
1989 JIT_DUMP_MAGIC
= 0x4A695444,
1990 JIT_DUMP_VERSION
= 2,
1992 ELF_MACHINE
= EM_386
,
1994 ELF_MACHINE
= EM_X86_64
,
1996 ELF_MACHINE
= EM_ARM
,
1998 ELF_MACHINE
= EM_AARCH64
,
1999 #elif HOST_POWERPC64
2000 ELF_MACHINE
= EM_PPC64
,
2002 ELF_MACHINE
= EM_S390
,
2004 ELF_MACHINE
= EM_RISCV
,
2006 ELF_MACHINE
= EM_MIPS
,
2007 #elif HOST_LOONGARCH64
2008 ELF_MACHINE
= EM_LOONGARCH
,
2031 RecordHeader header
;
2038 // Null terminated function name
2040 } JitCodeLoadRecord
;
2042 static void add_file_header_info (FileHeader
*header
);
2043 static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord
*record
);
2046 mono_enable_jit_dump (void)
2048 if (perf_dump_pid
== 0)
2049 perf_dump_pid
= getpid();
2051 if (!perf_dump_file
) {
2054 memset (&header
, 0, sizeof (header
));
2056 mono_os_mutex_init (&perf_dump_mutex
);
2057 mono_os_mutex_lock (&perf_dump_mutex
);
2059 g_snprintf (name
, sizeof (name
), "/tmp/jit-%d.dump", perf_dump_pid
);
2061 perf_dump_file
= fopen (name
, "w");
2063 add_file_header_info (&header
);
2064 if (perf_dump_file
) {
2065 fwrite (&header
, sizeof (header
), 1, perf_dump_file
);
2066 //This informs perf of the presence of the jitdump file and support for the feature.
2067 perf_dump_mmap_addr
= mmap (NULL
, sizeof (header
), PROT_READ
| PROT_EXEC
, MAP_PRIVATE
, fileno (perf_dump_file
), 0);
2070 mono_os_mutex_unlock (&perf_dump_mutex
);
2075 add_file_header_info (FileHeader
*header
)
2077 header
->magic
= JIT_DUMP_MAGIC
;
2078 header
->version
= JIT_DUMP_VERSION
;
2079 header
->total_size
= sizeof (header
);
2080 header
->elf_mach
= ELF_MACHINE
;
2082 header
->pid
= perf_dump_pid
;
2083 header
->timestamp
= mono_clock_get_time_ns (clock_id
);
2088 mono_emit_jit_dump (MonoJitInfo
*jinfo
, gpointer code
)
2090 static uint64_t code_index
;
2092 if (perf_dump_file
) {
2093 JitCodeLoadRecord record
;
2094 size_t nameLen
= strlen (jinfo
->d
.method
->name
);
2095 memset (&record
, 0, sizeof (record
));
2097 add_basic_JitCodeLoadRecord_info (&record
);
2098 record
.header
.total_size
= sizeof (record
) + nameLen
+ 1 + jinfo
->code_size
;
2099 record
.vma
= (guint64
)jinfo
->code_start
;
2100 record
.code_addr
= (guint64
)jinfo
->code_start
;
2101 record
.code_size
= (guint64
)jinfo
->code_size
;
2103 mono_os_mutex_lock (&perf_dump_mutex
);
2105 record
.code_index
= ++code_index
;
2107 // TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held).
2109 record
.header
.timestamp
= mono_clock_get_time_ns (clock_id
);
2111 fwrite (&record
, sizeof (record
), 1, perf_dump_file
);
2112 fwrite (jinfo
->d
.method
->name
, nameLen
+ 1, 1, perf_dump_file
);
2113 fwrite (code
, jinfo
->code_size
, 1, perf_dump_file
);
2115 mono_os_mutex_unlock (&perf_dump_mutex
);
2120 add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord
*record
)
2122 record
->header
.id
= JIT_CODE_LOAD
;
2123 record
->header
.timestamp
= mono_clock_get_time_ns (clock_id
);
2124 record
->pid
= perf_dump_pid
;
2125 record
->tid
= syscall (SYS_gettid
);
2129 mono_jit_dump_cleanup (void)
2131 if (perf_dump_mmap_addr
!= MAP_FAILED
)
2132 munmap (perf_dump_mmap_addr
, sizeof(FileHeader
));
2134 fclose (perf_dump_file
);
2140 mono_enable_jit_dump (void)
2145 mono_emit_jit_dump (MonoJitInfo
*jinfo
, gpointer code
)
2150 mono_jit_dump_cleanup (void)
2157 no_gsharedvt_in_wrapper (void)
2159 g_assert_not_reached ();
2165 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.
2166 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
2167 Dependency management in this case is too complex to justify implementing it.
2169 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
2172 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
2173 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
2174 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
2175 Maybe pool JitCompilationEntry, specially those with an inited cond var;
2180 int compilation_count
; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
2181 int ref_count
; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
2182 int threads_waiting
; /* Number of threads waiting on this job */
2183 gboolean has_cond
; /* True if @cond was initialized */
2184 gboolean done
; /* True if the method finished JIT'ing */
2185 MonoCoopCond cond
; /* Cond sleeping threads wait one */
2186 } JitCompilationEntry
;
2189 GPtrArray
*in_flight_methods
; //JitCompilationEntry*
2191 } JitCompilationData
;
2194 Timeout, in millisecounds, that we wait other threads to finish JITing.
2195 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.
2197 #define MAX_JIT_TIMEOUT_MS 1000
2200 static JitCompilationData compilation_data
;
2201 static int jit_methods_waited
, jit_methods_multiple
, jit_methods_overload
, jit_spurious_wakeups_or_timeouts
;
2204 mini_jit_init_job_control (void)
2206 mono_coop_mutex_init (&compilation_data
.lock
);
2207 compilation_data
.in_flight_methods
= g_ptr_array_new ();
2211 lock_compilation_data (void)
2213 mono_coop_mutex_lock (&compilation_data
.lock
);
2217 unlock_compilation_data (void)
2219 mono_coop_mutex_unlock (&compilation_data
.lock
);
2222 static JitCompilationEntry
*
2223 find_method (MonoMethod
*method
, MonoDomain
*domain
)
2226 for (i
= 0; i
< compilation_data
.in_flight_methods
->len
; ++i
){
2227 JitCompilationEntry
*e
= (JitCompilationEntry
*)compilation_data
.in_flight_methods
->pdata
[i
];
2228 if (e
->method
== method
&& e
->domain
== domain
)
2236 add_current_thread (MonoJitTlsData
*jit_tls
)
2238 ++jit_tls
->active_jit_methods
;
2242 unref_jit_entry (JitCompilationEntry
*entry
)
2245 if (entry
->ref_count
)
2247 if (entry
->has_cond
)
2248 mono_coop_cond_destroy (&entry
->cond
);
2253 * Returns true if this method waited successfully for another thread to JIT it
2256 wait_or_register_method_to_compile (MonoMethod
*method
, MonoDomain
*domain
)
2258 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2259 JitCompilationEntry
*entry
;
2261 static gboolean inited
;
2263 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_waited
);
2264 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_multiple
);
2265 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_overload
);
2266 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_spurious_wakeups_or_timeouts
);
2270 lock_compilation_data ();
2272 if (!(entry
= find_method (method
, domain
))) {
2273 entry
= g_new0 (JitCompilationEntry
, 1);
2274 entry
->method
= method
;
2275 entry
->domain
= domain
;
2276 entry
->compilation_count
= entry
->ref_count
= 1;
2277 g_ptr_array_add (compilation_data
.in_flight_methods
, entry
);
2278 g_assert (find_method (method
, domain
) == entry
);
2279 add_current_thread (jit_tls
);
2281 unlock_compilation_data ();
2283 } else if (jit_tls
->active_jit_methods
> 0 || mono_threads_is_current_thread_in_protected_block ()) {
2284 //We can't suspend the current thread if it's already JITing a method.
2285 //Dependency management is too compilated and we want to get rid of this anyways.
2287 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2288 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2290 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2291 ++entry
->compilation_count
;
2292 ++jit_methods_multiple
;
2293 ++jit_tls
->active_jit_methods
;
2295 unlock_compilation_data ();
2298 ++jit_methods_waited
;
2301 if (!entry
->has_cond
) {
2302 mono_coop_cond_init (&entry
->cond
);
2303 entry
->has_cond
= TRUE
;
2307 ++entry
->threads_waiting
;
2309 g_assert (entry
->has_cond
);
2310 mono_coop_cond_timedwait (&entry
->cond
, &compilation_data
.lock
, MAX_JIT_TIMEOUT_MS
);
2311 --entry
->threads_waiting
;
2314 unref_jit_entry (entry
);
2315 unlock_compilation_data ();
2318 //We hit the timeout or a spurious wakeup, fallback to JITing
2319 g_assert (entry
->ref_count
> 1);
2320 unref_jit_entry (entry
);
2321 ++jit_spurious_wakeups_or_timeouts
;
2323 ++entry
->compilation_count
;
2324 ++jit_methods_multiple
;
2325 ++jit_tls
->active_jit_methods
;
2327 unlock_compilation_data ();
2335 unregister_method_for_compile (MonoMethod
*method
, MonoDomain
*target_domain
)
2337 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2339 lock_compilation_data ();
2341 g_assert (jit_tls
->active_jit_methods
> 0);
2342 --jit_tls
->active_jit_methods
;
2344 JitCompilationEntry
*entry
= find_method (method
, target_domain
);
2345 g_assert (entry
); // It would be weird to fail
2348 if (entry
->threads_waiting
) {
2349 g_assert (entry
->has_cond
);
2350 mono_coop_cond_broadcast (&entry
->cond
);
2353 if (--entry
->compilation_count
== 0) {
2354 g_ptr_array_remove (compilation_data
.in_flight_methods
, entry
);
2355 unref_jit_entry (entry
);
2358 unlock_compilation_data ();
2362 create_jit_info_for_trampoline (MonoMethod
*wrapper
, MonoTrampInfo
*info
)
2364 MonoDomain
*domain
= mono_get_root_domain ();
2369 if (info
->uw_info
) {
2370 uw_info
= info
->uw_info
;
2371 info_len
= info
->uw_info_len
;
2373 uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, &info_len
);
2376 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
);
2377 jinfo
->d
.method
= wrapper
;
2378 jinfo
->code_start
= MINI_FTNPTR_TO_ADDR (info
->code
);
2379 jinfo
->code_size
= info
->code_size
;
2380 jinfo
->unwind_info
= mono_cache_unwind_info (uw_info
, info_len
);
2389 compile_special (MonoMethod
*method
, MonoDomain
*target_domain
, MonoError
*error
)
2394 if (mono_llvm_only
) {
2395 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2396 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2398 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
) {
2400 * These wrappers are only created for signatures which are in the program, but
2401 * sometimes we load methods too eagerly and have to create them even if they
2402 * will never be called.
2404 return (gpointer
)no_gsharedvt_in_wrapper
;
2409 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
2410 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
2411 MonoMethodPInvoke
* piinfo
= (MonoMethodPInvoke
*) method
;
2413 if (!piinfo
->addr
) {
2414 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
2415 guint32 flags
= MONO_ICALL_FLAGS_NONE
;
2416 gpointer icall_addr
;
2417 icall_addr
= (gpointer
)mono_lookup_internal_call_full_with_flags (method
, TRUE
, (guint32
*)&flags
);
2418 if (flags
& MONO_ICALL_FLAGS_NO_WRAPPER
) {
2419 piinfo
->icflags
= MONO_ICALL_FLAGS_NO_WRAPPER
;
2420 mono_memory_write_barrier ();
2422 piinfo
->addr
= icall_addr
;
2423 } else if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
) {
2425 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
);
2427 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
);
2430 ERROR_DECL (ignored_error
);
2431 mono_lookup_pinvoke_call_internal (method
, ignored_error
);
2432 mono_error_cleanup (ignored_error
);
2436 mono_memory_read_barrier ();
2438 gpointer compiled_method
= NULL
;
2439 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) && (piinfo
->icflags
& MONO_ICALL_FLAGS_NO_WRAPPER
)) {
2440 compiled_method
= piinfo
->addr
;
2442 MonoMethod
*nm
= mono_marshal_get_native_wrapper (method
, TRUE
, mono_aot_only
);
2443 compiled_method
= mono_jit_compile_method_jit_only (nm
, error
);
2444 return_val_if_nok (error
, NULL
);
2447 code
= mono_get_addr_from_ftnptr (compiled_method
);
2448 jinfo
= mono_jit_info_table_find (target_domain
, code
);
2450 jinfo
= mono_jit_info_table_find (mono_domain_get (), code
);
2452 MONO_PROFILER_RAISE (jit_done
, (method
, jinfo
));
2454 } else if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
2455 const char *name
= method
->name
;
2459 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2460 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
2461 MonoJitICallInfo
*mi
= &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor
;
2463 * We need to make sure this wrapper
2464 * is compiled because it might end up
2465 * in an (M)RGCTX if generic sharing
2466 * is enabled, and would be called
2467 * indirectly. If it were a
2468 * trampoline we'd try to patch that
2469 * indirect call, which is not
2472 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper_full (mi
, TRUE
));
2473 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2474 if (mono_llvm_only
) {
2475 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
2476 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2477 return_val_if_nok (error
, NULL
);
2478 return mono_get_addr_from_ftnptr (compiled_ptr
);
2481 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2482 if (mono_use_interpreter
)
2485 return mono_create_delegate_trampoline (target_domain
, method
->klass
);
2486 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
2487 nm
= mono_marshal_get_delegate_begin_invoke (method
);
2488 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2489 return_val_if_nok (error
, NULL
);
2490 return mono_get_addr_from_ftnptr (compiled_ptr
);
2491 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
2492 nm
= mono_marshal_get_delegate_end_invoke (method
);
2493 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2494 return_val_if_nok (error
, NULL
);
2495 return mono_get_addr_from_ftnptr (compiled_ptr
);
2499 full_name
= mono_method_full_name (method
, TRUE
);
2500 mono_error_set_invalid_program (error
, "Unrecognizable runtime implemented method '%s'", full_name
);
2505 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2506 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2508 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
|| info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_OUT
) {
2509 static MonoTrampInfo
*in_tinfo
, *out_tinfo
;
2510 MonoTrampInfo
*tinfo
;
2512 gboolean is_in
= info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
;
2514 if (is_in
&& in_tinfo
)
2515 return in_tinfo
->code
;
2516 else if (!is_in
&& out_tinfo
)
2517 return out_tinfo
->code
;
2520 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2522 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2524 if (mono_ee_features
.use_aot_trampolines
)
2525 mono_aot_get_trampoline_full (is_in
? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo
);
2527 mono_arch_get_gsharedvt_trampoline (&tinfo
, FALSE
);
2528 jinfo
= create_jit_info_for_trampoline (method
, tinfo
);
2529 mono_jit_info_table_add (mono_get_root_domain (), jinfo
);
2542 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
2544 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
2546 gpointer code
= NULL
, p
;
2547 MonoJitICallInfo
*callinfo
= NULL
;
2548 WrapperInfo
*winfo
= NULL
;
2549 gboolean use_interp
= FALSE
;
2553 if (mono_ee_features
.force_use_interpreter
&& !jit_only
)
2555 if (!use_interp
&& mono_interp_only_classes
) {
2556 for (GSList
*l
= mono_interp_only_classes
; l
; l
= l
->next
) {
2557 if (!strcmp (m_class_get_name (method
->klass
), (char*)l
->data
))
2562 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2568 /* Should be handled by the caller */
2569 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
2572 * ICALL wrappers are handled specially, since there is only one copy of them
2573 * shared by all appdomains.
2575 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2576 winfo
= mono_marshal_get_wrapper_info (method
);
2577 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
2578 callinfo
= mono_find_jit_icall_info (winfo
->d
.icall
.jit_icall_id
);
2580 /* Must be domain neutral since there is only one copy */
2581 opt
|= MONO_OPT_SHARED
;
2583 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2584 opt
&= ~MONO_OPT_SHARED
;
2587 if (opt
& MONO_OPT_SHARED
)
2588 target_domain
= mono_get_root_domain ();
2590 target_domain
= domain
;
2592 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2593 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2596 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
2597 MonoGenericContext
*ctx
= NULL
;
2598 if (method
->is_inflated
)
2599 ctx
= mono_method_get_context (method
);
2600 method
= info
->d
.synchronized_inner
.method
;
2602 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2603 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
2609 info
= lookup_method (target_domain
, method
);
2611 /* We can't use a domain specific method in another domain */
2612 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2615 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2616 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2620 if (!mono_runtime_class_init_full (vtable
, error
))
2623 code
= MINI_ADDR_TO_FTNPTR (info
->code_start
);
2624 return mono_create_ftnptr (target_domain
, code
);
2628 #ifdef MONO_USE_AOT_COMPILER
2629 if (opt
& MONO_OPT_AOT
) {
2630 MonoDomain
*domain
= NULL
;
2632 if (mono_aot_mode
== MONO_AOT_MODE_INTERP
&& method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2633 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2635 if (info
->subtype
== WRAPPER_SUBTYPE_INTERP_IN
|| info
->subtype
== WRAPPER_SUBTYPE_INTERP_LMF
)
2636 /* AOT'd wrappers for interp must be owned by root domain */
2637 domain
= mono_get_root_domain ();
2641 domain
= mono_domain_get ();
2643 mono_class_init_internal (method
->klass
);
2645 code
= mono_aot_get_method (domain
, method
, error
);
2649 if (mono_gc_is_critical_method (method
)) {
2651 * The suspend code needs to be able to lookup these methods by ip in async context,
2652 * so preload their jit info.
2654 MonoJitInfo
*ji
= mini_jit_info_table_find (domain
, code
, NULL
);
2659 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2660 * This is not a problem, since it will be initialized when the method is first
2661 * called by init_method ().
2663 if (!mono_llvm_only
&& !mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2664 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2665 mono_error_assert_ok (error
);
2666 if (!mono_runtime_class_init_full (vtable
, error
))
2676 code
= compile_special (method
, target_domain
, error
);
2682 if (!jit_only
&& !code
&& mono_aot_only
&& mono_use_interpreter
&& method
->wrapper_type
!= MONO_WRAPPER_OTHER
) {
2683 if (mono_llvm_only
) {
2684 /* Signal to the caller that AOTed code is not found */
2687 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2694 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2695 char *full_name
= mono_type_get_full_name (method
->klass
);
2696 mono_error_set_invalid_operation (error
, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name
);
2701 if (mono_aot_only
) {
2702 char *fullname
= mono_method_get_full_name (method
);
2703 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
);
2709 if (wait_or_register_method_to_compile (method
, target_domain
))
2711 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2712 unregister_method_for_compile (method
, target_domain
);
2717 if (!code
&& mono_llvm_only
) {
2718 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2719 g_assert_not_reached ();
2725 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2727 if ((method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
)) {
2731 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2733 MonoJitInfo
*ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2738 p
= mono_create_ftnptr (target_domain
, code
);
2741 // FIXME Locking here is somewhat historical due to mono_register_jit_icall_wrapper taking loader lock.
2742 // atomic_compare_exchange should suffice.
2743 mono_loader_lock ();
2745 if (!callinfo
->wrapper
) {
2746 callinfo
->wrapper
= p
;
2749 mono_loader_unlock ();
2752 // FIXME p or callinfo->wrapper or does not matter?
2757 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2761 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2766 * mono_jit_compile_method_jit_only:
2768 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2771 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2775 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2779 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2781 invalidated_delegate_trampoline (char *desc
)
2783 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2784 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2790 * mono_jit_free_method:
2792 * Free all memory allocated by the JIT for METHOD.
2795 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2797 MonoJitDynamicMethodInfo
*ji
;
2798 gboolean destroy
= TRUE
, removed
;
2799 GHashTableIter iter
;
2800 MonoJumpList
*jlist
;
2801 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2803 g_assert (method
->dynamic
);
2805 if (mono_use_interpreter
) {
2806 mini_get_interp_callbacks ()->free_method (domain
, method
);
2809 mono_domain_lock (domain
);
2810 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2811 mono_domain_unlock (domain
);
2816 mono_debug_remove_method (method
, domain
);
2817 mono_lldb_remove_method (domain
, method
, ji
);
2819 mono_domain_lock (domain
);
2820 g_hash_table_remove (info
->dynamic_code_hash
, method
);
2821 mono_domain_jit_code_hash_lock (domain
);
2822 removed
= mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2824 mono_domain_jit_code_hash_unlock (domain
);
2825 g_hash_table_remove (info
->jump_trampoline_hash
, method
);
2826 g_hash_table_remove (info
->seq_points
, method
);
2828 ji
->ji
->seq_points
= NULL
;
2830 /* requires the domain lock - took above */
2831 mono_conc_hashtable_remove (info
->runtime_invoke_hash
, method
);
2833 /* Remove jump targets in this method */
2834 g_hash_table_iter_init (&iter
, info
->jump_target_hash
);
2835 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2836 GSList
*tmp
, *remove
;
2839 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2840 guint8
*ip
= (guint8
*)tmp
->data
;
2842 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2843 remove
= g_slist_prepend (remove
, tmp
);
2845 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2846 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2848 g_slist_free (remove
);
2850 mono_domain_unlock (domain
);
2852 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2853 if (mini_debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2855 * Instead of freeing the code, change it to call an error routine
2856 * so people can fix their code.
2858 char *type
= mono_type_full_name (m_class_get_byval_arg (method
->klass
));
2859 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2862 mono_arch_invalidate_method (ji
->ji
, (gpointer
)invalidated_delegate_trampoline
, (gpointer
)type_and_method
);
2868 * This needs to be done before freeing code_mp, since the code address is the
2869 * key in the table, so if we free the code_mp first, another thread can grab the
2870 * same code address and replace our entry in the table.
2872 mono_jit_info_table_remove (domain
, ji
->ji
);
2875 mono_code_manager_destroy (ji
->code_mp
);
2880 mono_jit_search_all_backends_for_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**out_ji
)
2885 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
2887 ERROR_DECL (oerror
);
2889 /* Might be AOTed code */
2890 mono_class_init_internal (method
->klass
);
2891 code
= mono_aot_get_method (domain
, method
, oerror
);
2893 mono_error_assert_ok (oerror
);
2894 ji
= mono_jit_info_table_find (domain
, code
);
2896 if (!is_ok (oerror
))
2897 mono_error_cleanup (oerror
);
2899 /* Might be interpreted */
2900 ji
= mini_get_interp_callbacks ()->find_jit_info (domain
, method
);
2910 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2912 MonoDomain
*target_domain
;
2915 if (default_opt
& MONO_OPT_SHARED
)
2916 target_domain
= mono_get_root_domain ();
2918 target_domain
= domain
;
2920 info
= lookup_method (target_domain
, method
);
2922 /* We can't use a domain specific method in another domain */
2923 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2924 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2927 return MINI_ADDR_TO_FTNPTR (info
->code_start
);
2936 static guint32 bisect_opt
= 0;
2937 static GHashTable
*bisect_methods_hash
= NULL
;
2940 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2943 char method_name
[2048];
2946 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2947 g_assert (bisect_methods_hash
);
2949 file
= fopen (method_list_filename
, "r");
2952 while (fgets (method_name
, sizeof (method_name
), file
)) {
2953 size_t len
= strlen (method_name
);
2955 g_assert (method_name
[len
- 1] == '\n');
2956 method_name
[len
- 1] = 0;
2957 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2959 g_assert (feof (file
));
2962 gboolean mono_do_single_method_regression
= FALSE
;
2963 guint32 mono_single_method_regression_opt
= 0;
2964 MonoMethod
*mono_current_single_method
;
2965 GSList
*mono_single_method_list
;
2966 GHashTable
*mono_single_method_hash
;
2969 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 opt
)
2973 if (bisect_methods_hash
) {
2974 char *name
= mono_method_full_name (method
, TRUE
);
2975 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2978 return opt
| bisect_opt
;
2980 if (!mono_do_single_method_regression
)
2982 if (!mono_current_single_method
) {
2983 if (!mono_single_method_hash
)
2984 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2985 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2986 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2987 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2991 if (method
== mono_current_single_method
)
2992 return mono_single_method_regression_opt
;
2997 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2999 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
3004 gpointer compiled_method
;
3005 gpointer runtime_invoke
;
3007 MonoDynCallInfo
*dyn_call_info
;
3008 MonoClass
*ret_box_class
;
3009 MonoMethodSignature
*sig
;
3010 gboolean gsharedvt_invoke
;
3011 gboolean use_interp
;
3012 gpointer
*wrapper_arg
;
3013 } RuntimeInvokeInfo
;
3015 static RuntimeInvokeInfo
*
3016 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, gboolean use_interp
, MonoError
*error
)
3019 RuntimeInvokeInfo
*info
= NULL
;
3020 RuntimeInvokeInfo
*ret
= NULL
;
3022 info
= g_new0 (RuntimeInvokeInfo
, 1);
3023 info
->compiled_method
= compiled_method
;
3024 info
->use_interp
= use_interp
;
3025 if (mono_llvm_only
&& method
->string_ctor
)
3026 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
3028 info
->sig
= mono_method_signature_internal (method
);
3030 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
3032 info
->vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
3035 g_assert (info
->vtable
);
3037 MonoMethodSignature
*sig
;
3042 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
3043 * in full-aot mode, so we use a slower, but more generic wrapper if
3044 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
3046 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3047 if (!mono_llvm_only
&& (mono_aot_only
|| mini_debug_options
.dyn_runtime_invoke
)) {
3048 gboolean supported
= TRUE
;
3051 if (method
->string_ctor
)
3052 sig
= mono_marshal_get_string_ctor_signature (method
);
3054 for (i
= 0; i
< sig
->param_count
; ++i
) {
3055 MonoType
*t
= sig
->params
[i
];
3057 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
3061 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
3065 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
3066 if (mini_debug_options
.dyn_runtime_invoke
)
3067 g_assert (info
->dyn_call_info
);
3072 ret_type
= sig
->ret
;
3073 switch (ret_type
->type
) {
3074 case MONO_TYPE_VOID
:
3086 case MONO_TYPE_BOOLEAN
:
3087 case MONO_TYPE_CHAR
:
3090 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
3093 info
->ret_box_class
= mono_defaults
.int_class
;
3095 case MONO_TYPE_STRING
:
3096 case MONO_TYPE_CLASS
:
3097 case MONO_TYPE_ARRAY
:
3098 case MONO_TYPE_SZARRAY
:
3099 case MONO_TYPE_OBJECT
:
3101 case MONO_TYPE_GENERICINST
:
3102 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
3103 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
3105 case MONO_TYPE_VALUETYPE
:
3106 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
3109 g_assert_not_reached ();
3113 if (info
->use_interp
) {
3119 if (!info
->dyn_call_info
) {
3120 if (mono_llvm_only
) {
3121 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
3122 g_assert_not_reached ();
3124 info
->gsharedvt_invoke
= TRUE
;
3125 if (!callee_gsharedvt
) {
3126 /* Invoke a gsharedvt out wrapper instead */
3127 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
3128 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
3130 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
3131 info
->wrapper_arg
[0] = mini_llvmonly_add_method_wrappers (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
3133 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
3134 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
3135 g_free (wrapper_sig
);
3137 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
3141 /* Gsharedvt methods can be invoked the same way */
3142 /* The out wrapper has the same signature as the compiled gsharedvt method */
3143 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
3145 info
->wrapper_arg
= (gpointer
*)(mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
);
3147 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
3148 g_free (wrapper_sig
);
3151 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
3164 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
3166 MonoMethodSignature
*sig
= info
->sig
;
3167 MonoDomain
*domain
= mono_domain_get ();
3168 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
3169 gpointer retval_ptr
;
3170 guint8 retval
[256];
3175 g_assert (info
->gsharedvt_invoke
);
3178 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
3179 * The advantage of this is the gsharedvt out wrappers have a reduced set of
3180 * signatures, so we only have to generate runtime invoke wrappers for these
3182 * This code also handles invocation of gsharedvt methods directly, no
3183 * out wrappers are used in that case.
3185 // allocate param_refs = param_count and args = param_count + hasthis + 2.
3186 int const param_count
= sig
->param_count
;
3187 gpointer
* const param_refs
= g_newa (gpointer
, param_count
* 2 + sig
->hasthis
+ 2);
3188 gpointer
* const args
= param_refs
+ param_count
;
3191 * The runtime invoke wrappers expects pointers to primitive types, so have to
3195 args
[pindex
++] = &obj
;
3196 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3197 retval_ptr
= &retval
;
3198 args
[pindex
++] = &retval_ptr
;
3200 for (i
= 0; i
< sig
->param_count
; ++i
) {
3201 MonoType
*t
= sig
->params
[i
];
3203 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
3204 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
3205 guint8
*nullable_buf
;
3208 size
= mono_class_value_size (klass
, NULL
);
3209 nullable_buf
= g_alloca (size
);
3210 g_assert (nullable_buf
);
3212 /* The argument pointed to by params [i] is either a boxed vtype or null */
3213 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
3214 params
[i
] = nullable_buf
;
3217 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
3218 param_refs
[i
] = params
[i
];
3219 params
[i
] = &(param_refs
[i
]);
3221 args
[pindex
++] = ¶ms
[i
];
3223 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
3224 args
[pindex
++] = &info
->wrapper_arg
;
3226 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3228 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
3232 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3233 if (info
->ret_box_class
)
3234 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3236 return *(MonoObject
**)retval
;
3243 * mono_jit_runtime_invoke:
3244 * \param method: the method to invoke
3245 * \param obj: this pointer
3246 * \param params: array of parameter values.
3247 * \param exc: Set to the exception raised in the managed method.
3248 * \param error: error or caught exception object
3249 * If \p exc is NULL, \p error is thrown instead.
3250 * If coop is enabled, \p exc argument is ignored -
3251 * all exceptions are caught and propagated through \p error
3254 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
3256 MonoMethod
*invoke
, *callee
;
3257 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
3258 MonoDomain
*domain
= mono_domain_get ();
3259 MonoJitDomainInfo
*domain_info
;
3260 RuntimeInvokeInfo
*info
, *info2
;
3261 MonoJitInfo
*ji
= NULL
;
3262 gboolean callee_gsharedvt
= FALSE
;
3264 if (mono_ee_features
.force_use_interpreter
)
3265 return mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3271 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
3272 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3276 domain_info
= domain_jit_info (domain
);
3278 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
3281 if (mono_security_core_clr_enabled ()) {
3283 * This might be redundant since mono_class_vtable () already does this,
3284 * but keep it just in case for moonlight.
3286 mono_class_setup_vtable (method
->klass
);
3287 if (mono_class_has_failure (method
->klass
)) {
3288 mono_error_set_for_class_failure (error
, method
->klass
);
3290 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
3295 gpointer compiled_method
;
3298 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3299 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3301 * Array Get/Set/Address methods. The JIT implements them using inline code
3302 * inside the runtime invoke wrappers, so no need to compile them.
3304 if (mono_aot_only
) {
3306 * Call a wrapper, since the runtime invoke wrapper was not generated.
3308 MonoMethod
*wrapper
;
3310 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
3311 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
3318 gboolean use_interp
= FALSE
;
3321 compiled_method
= mono_jit_compile_method_jit_only (callee
, error
);
3322 if (!compiled_method
) {
3323 g_assert (!is_ok (error
));
3325 if (mono_use_interpreter
)
3330 if (mono_llvm_only
) {
3331 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
3332 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3333 if (callee_gsharedvt
)
3334 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
3337 if (!callee_gsharedvt
)
3338 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
3341 compiled_method
= NULL
;
3344 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, use_interp
, error
);
3348 mono_domain_lock (domain
);
3349 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
3350 mono_domain_unlock (domain
);
3358 * We need this here because mono_marshal_get_runtime_invoke can place
3359 * the helper method in System.Object and not the target class.
3361 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
3363 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3367 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3368 we always catch the exception and propagate it through the MonoError */
3369 gboolean catchExcInMonoError
=
3370 (exc
== NULL
) && mono_threads_are_safepoints_enabled ();
3371 MonoObject
*invoke_exc
= NULL
;
3372 if (catchExcInMonoError
)
3375 /* The wrappers expect this to be initialized to NULL */
3379 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3380 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
= NULL
;
3381 if (info
->dyn_call_info
) {
3382 if (!dyn_runtime_invoke
) {
3383 mono_domain_lock (domain
);
3385 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
3386 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method_jit_only (invoke
, error
);
3387 if (!dyn_runtime_invoke
&& mono_use_interpreter
) {
3388 info
->use_interp
= TRUE
;
3389 info
->dyn_call_info
= NULL
;
3390 } else if (!is_ok (error
)) {
3391 mono_domain_unlock (domain
);
3394 mono_domain_unlock (domain
);
3397 if (info
->dyn_call_info
) {
3398 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
3400 int i
, pindex
, buf_size
;
3402 guint8 retval
[256];
3404 /* Convert the arguments to the format expected by start_dyn_call () */
3405 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
3408 args
[pindex
++] = &obj
;
3409 for (i
= 0; i
< sig
->param_count
; ++i
) {
3410 MonoType
*t
= sig
->params
[i
];
3413 args
[pindex
++] = ¶ms
[i
];
3414 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
3415 args
[pindex
++] = ¶ms
[i
];
3417 args
[pindex
++] = params
[i
];
3421 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3423 buf_size
= mono_arch_dyn_call_get_buf_size (info
->dyn_call_info
);
3424 buf
= g_alloca (buf_size
);
3425 memset (buf
, 0, buf_size
);
3428 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
);
3430 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
3431 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
3433 if (catchExcInMonoError
&& *exc
!= NULL
) {
3434 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3438 if (info
->ret_box_class
)
3439 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3441 return *(MonoObject
**)retval
;
3447 if (info
->use_interp
) {
3448 result
= mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3449 return_val_if_nok (error
, NULL
);
3450 } else if (mono_llvm_only
) {
3451 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
3455 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3457 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
3459 if (catchExcInMonoError
&& *exc
!= NULL
) {
3460 ((MonoException
*)(*exc
))->caught_in_unmanaged
= TRUE
;
3461 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3466 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
3468 MonoException
*exc
= NULL
;
3471 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3472 MONO_SIG_HANDLER_GET_CONTEXT
;
3474 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3476 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3478 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3479 if (mono_arch_is_int_overflow (ctx
, info
))
3481 * The spec says this throws ArithmeticException, but MS throws the derived
3482 * OverflowException.
3484 exc
= mono_get_exception_overflow ();
3486 exc
= mono_get_exception_divide_by_zero ();
3488 exc
= mono_get_exception_divide_by_zero ();
3492 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3495 mono_sigctx_to_monoctx (ctx
, &mctx
);
3496 if (mono_dump_start ())
3497 mono_handle_native_crash (mono_get_signame (SIGFPE
), &mctx
, info
);
3498 if (mono_do_crash_chaining
) {
3499 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3504 mono_arch_handle_exception (ctx
, exc
);
3507 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3510 MONO_SIG_HANDLER_FUNC (, mono_crashing_signal_handler
)
3513 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3514 MONO_SIG_HANDLER_GET_CONTEXT
;
3516 if (mono_runtime_get_no_exec ())
3519 mono_sigctx_to_monoctx (ctx
, &mctx
);
3520 if (mono_dump_start ())
3521 #if defined(HAVE_SIG_INFO) && !defined(HOST_WIN32) // info is a siginfo_t
3522 mono_handle_native_crash (mono_get_signame (info
->si_signo
), &mctx
, info
);
3524 mono_handle_native_crash (mono_get_signame (SIGTERM
), &mctx
, info
);
3526 if (mono_do_crash_chaining
) {
3527 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3532 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3534 #define HAVE_SIG_INFO
3535 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3537 #ifdef MONO_SIG_HANDLER_DEBUG
3538 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3539 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3540 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3541 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3542 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3543 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3549 mono_is_addr_implicit_null_check (void *addr
)
3551 /* implicit null checks are only expected to work on the first page. larger
3552 * offsets are expected to have an explicit null check */
3553 return addr
<= GUINT_TO_POINTER (mono_target_pagesize ());
3556 // This function is separate from mono_sigsegv_signal_handler
3557 // so debug_fault_addr can be seen in debugger stacks.
3558 #ifdef MONO_SIG_HANDLER_DEBUG
3560 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug
)
3562 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3565 MonoJitInfo
*ji
= NULL
;
3566 MonoDomain
*domain
= mono_domain_get ();
3567 gpointer fault_addr
= NULL
;
3570 #if defined(HAVE_SIG_INFO) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3571 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3573 #ifdef HAVE_SIG_INFO
3574 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3578 MONO_SIG_HANDLER_GET_CONTEXT
;
3580 mono_sigctx_to_monoctx (ctx
, &mctx
);
3582 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3583 if (mono_arch_is_single_step_event (info
, ctx
)) {
3584 mini_get_dbg_callbacks ()->single_step_event (ctx
);
3586 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3587 mini_get_dbg_callbacks ()->breakpoint_hit (ctx
);
3592 #if defined(HAVE_SIG_INFO)
3593 #if !defined(HOST_WIN32)
3594 fault_addr
= info
->si_addr
;
3595 if (mono_aot_is_pagefault (info
->si_addr
)) {
3596 mono_aot_handle_pagefault (info
->si_addr
);
3599 int signo
= info
->si_signo
;
3601 int signo
= SIGSEGV
;
3604 /* The thread might no be registered with the runtime */
3605 if (!mono_domain_get () || !jit_tls
) {
3606 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3608 if (mono_dump_start())
3609 mono_handle_native_crash (mono_get_signame (signo
), &mctx
, info
);
3610 if (mono_do_crash_chaining
) {
3611 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3614 /* thread not registered with the runtime, make sure we return now. */
3620 gpointer ip
= MINI_FTNPTR_TO_ADDR (mono_arch_ip_from_context (ctx
));
3621 ji
= mono_jit_info_table_find_internal (domain
, ip
, TRUE
, TRUE
);
3624 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3625 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3628 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3629 fault_addr
= info
->si_addr
;
3630 if (fault_addr
== NULL
) {
3631 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3634 if (jit_tls
&& jit_tls
->stack_size
&&
3635 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3637 * The hard-guard page has been hit: there is not much we can do anymore
3638 * Print a hopefully clear message and abort.
3640 mono_handle_hard_stack_ovf (jit_tls
, ji
, &mctx
, (guint8
*)info
->si_addr
);
3641 g_assert_not_reached ();
3643 /* The original handler might not like that it is executed on an altstack... */
3644 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3648 /* exceptions-amd64.c handles the check itself */
3649 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3651 if (mono_is_addr_implicit_null_check (info
->si_addr
)) {
3652 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3654 // FIXME: This shouldn't run on the altstack
3655 if (mono_dump_start ())
3656 mono_handle_native_crash (mono_get_signame (SIGSEGV
), &mctx
, info
);
3663 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3666 if (mono_dump_start ())
3667 mono_handle_native_crash (mono_get_signame (SIGSEGV
), &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3669 if (mono_do_crash_chaining
) {
3670 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3675 if (mono_is_addr_implicit_null_check (fault_addr
)) {
3676 mono_arch_handle_exception (ctx
, NULL
);
3678 if (mono_dump_start ())
3679 mono_handle_native_crash (mono_get_signame (SIGSEGV
), &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3680 if (mono_do_crash_chaining
) {
3681 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3688 #ifdef MONO_SIG_HANDLER_DEBUG
3690 // This function is separate from mono_sigsegv_signal_handler_debug
3691 // so debug_fault_addr can be seen in debugger stacks.
3692 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3695 gpointer
const debug_fault_addr
= (gpointer
)MONO_SIG_HANDLER_GET_INFO () ->ep
->ExceptionRecord
->ExceptionInformation
[1];
3696 #elif defined (HAVE_SIG_INFO)
3697 gpointer
const debug_fault_addr
= MONO_SIG_HANDLER_GET_INFO ()->si_addr
;
3699 #error No extra parameter is passed, not even 0, to avoid any confusion.
3701 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG
);
3704 #endif // MONO_SIG_HANDLER_DEBUG
3706 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3709 MONO_SIG_HANDLER_GET_CONTEXT
;
3711 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3713 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3715 mono_arch_handle_exception (ctx
, exc
);
3717 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3720 #ifndef DISABLE_REMOTING
3721 /* mono_jit_create_remoting_trampoline:
3722 * @method: pointer to the method info
3724 * Creates a trampoline which calls the remoting functions. This
3725 * is used in the vtable of transparent proxies.
3727 * Returns: a pointer to the newly created code
3730 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3733 guint8
*addr
= NULL
;
3737 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature_internal (method
)->generic_param_count
) {
3738 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3742 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3743 (mono_method_signature_internal (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3744 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
, error
);
3747 return_val_if_nok (error
, NULL
);
3748 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3749 return_val_if_nok (error
, NULL
);
3750 return mono_get_addr_from_ftnptr (addr
);
3754 static G_GNUC_UNUSED
void
3755 no_imt_trampoline (void)
3757 g_assert_not_reached ();
3760 static G_GNUC_UNUSED
void
3761 no_vcall_trampoline (void)
3763 g_assert_not_reached ();
3766 static gpointer
*vtable_trampolines
;
3767 static int vtable_trampolines_size
;
3770 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3772 int index
= slot_index
+ MONO_IMT_SIZE
;
3775 return mini_llvmonly_get_vtable_trampoline (vt
, slot_index
, index
);
3777 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3778 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3780 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3784 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3785 while (new_size
<= index
)
3787 new_table
= g_new0 (gpointer
, new_size
);
3789 if (vtable_trampolines
)
3790 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3791 g_free (vtable_trampolines
);
3792 mono_memory_barrier ();
3793 vtable_trampolines
= (void **)new_table
;
3794 vtable_trampolines_size
= new_size
;
3799 if (!vtable_trampolines
[index
])
3800 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3801 return vtable_trampolines
[index
];
3805 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3807 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3811 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3816 gpointer
*imt
= (gpointer
*)vt
;
3817 imt
-= MONO_IMT_SIZE
;
3819 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3823 create_delegate_method_ptr (MonoMethod
*method
, MonoError
*error
)
3827 if (method_is_dynamic (method
)) {
3828 /* Creating a trampoline would leak memory */
3829 func
= mono_compile_method_checked (method
, error
);
3830 return_val_if_nok (error
, NULL
);
3832 gpointer trampoline
= mono_create_jump_trampoline (mono_domain_get (), method
, TRUE
, error
);
3833 return_val_if_nok (error
, NULL
);
3834 func
= mono_create_ftnptr (mono_domain_get (), trampoline
);
3840 mini_init_delegate (MonoDelegateHandle delegate
, MonoObjectHandle target
, gpointer addr
, MonoMethod
*method
, MonoError
*error
)
3842 MonoDelegate
*del
= MONO_HANDLE_RAW (delegate
);
3843 MonoDomain
*domain
= MONO_HANDLE_DOMAIN (delegate
);
3847 gpointer lookup_addr
= MINI_FTNPTR_TO_ADDR (addr
);
3850 ji
= mono_jit_info_table_find_internal (domain
, mono_get_addr_from_ftnptr (lookup_addr
), TRUE
, TRUE
);
3852 if (!ji
&& domain
!= mono_get_root_domain ())
3853 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), mono_get_addr_from_ftnptr (lookup_addr
), TRUE
, TRUE
);
3855 if (ji
->is_trampoline
) {
3856 /* Could be an unbox trampoline etc. */
3857 method
= ji
->d
.tramp_info
->method
;
3859 method
= mono_jit_info_get_method (ji
);
3860 g_assert (!mono_class_is_gtd (method
->klass
));
3866 MONO_HANDLE_SETVAL (delegate
, method
, MonoMethod
*, method
);
3869 MONO_HANDLE_SETVAL (delegate
, method_ptr
, gpointer
, addr
);
3871 #ifndef DISABLE_REMOTING
3872 if (!MONO_HANDLE_IS_NULL (target
) && mono_class_is_transparent_proxy (mono_handle_class (target
))) {
3873 if (mono_use_interpreter
) {
3874 MONO_HANDLE_SETVAL (delegate
, interp_method
, gpointer
, mini_get_interp_callbacks ()->get_remoting_invoke (method
, addr
, error
));
3877 method
= mono_marshal_get_remoting_invoke (method
, error
);
3878 return_if_nok (error
);
3879 MONO_HANDLE_SETVAL (delegate
, method_ptr
, gpointer
, mono_compile_method_checked (method
, error
));
3881 return_if_nok (error
);
3885 MONO_HANDLE_SET (delegate
, target
, target
);
3886 MONO_HANDLE_SETVAL (delegate
, invoke_impl
, gpointer
, mono_create_delegate_trampoline (domain
, mono_handle_class (delegate
)));
3888 if (mono_use_interpreter
) {
3889 mini_get_interp_callbacks ()->init_delegate (del
, error
);
3890 return_if_nok (error
);
3893 if (mono_llvm_only
) {
3894 g_assert (del
->method
);
3895 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3896 del
->method_ptr
= mini_llvmonly_load_method_delegate (del
->method
, FALSE
, FALSE
, &del
->extra_arg
, error
);
3897 } else if (!del
->method_ptr
) {
3898 del
->method_ptr
= create_delegate_method_ptr (del
->method
, error
);
3899 return_if_nok (error
);
3904 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3908 abs_offset
= offset
;
3910 abs_offset
= - abs_offset
;
3911 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ TARGET_SIZEOF_VOID_P
);
3915 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3917 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3920 static guint8
**cache
= NULL
;
3921 static int cache_size
= 0;
3926 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3929 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3930 is_interface
= mono_class_is_interface (method
->klass
);
3931 load_imt_reg
= is_virtual_generic
|| is_interface
;
3934 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
3936 offset
= MONO_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
3938 idx
= (offset
/ TARGET_SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3939 g_assert (idx
>= 0);
3941 /* Resize the cache to idx + 1 */
3942 if (cache_size
< idx
+ 1) {
3944 if (cache_size
< idx
+ 1) {
3946 int new_cache_size
= idx
+ 1;
3948 new_cache
= g_new0 (guint8
*, new_cache_size
);
3950 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3953 mono_memory_barrier ();
3955 cache_size
= new_cache_size
;
3963 /* FIXME Support more cases */
3964 if (mono_ee_features
.use_aot_trampolines
) {
3965 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3966 g_assert (cache
[idx
]);
3968 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3974 * mini_parse_debug_option:
3975 * @option: The option to parse.
3977 * Parses debug options for the mono runtime. The options are the same as for
3978 * the MONO_DEBUG environment variable.
3982 mini_parse_debug_option (const char *option
)
3984 // Empty string is ok as consequence of appending ",foo"
3985 // without first checking for empty.
3989 if (!strcmp (option
, "handle-sigint"))
3990 mini_debug_options
.handle_sigint
= TRUE
;
3991 else if (!strcmp (option
, "keep-delegates"))
3992 mini_debug_options
.keep_delegates
= TRUE
;
3993 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3994 mini_debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3995 else if (!strcmp (option
, "collect-pagefault-stats"))
3996 mini_debug_options
.collect_pagefault_stats
= TRUE
;
3997 else if (!strcmp (option
, "break-on-unverified"))
3998 mini_debug_options
.break_on_unverified
= TRUE
;
3999 else if (!strcmp (option
, "no-gdb-backtrace"))
4000 mini_debug_options
.no_gdb_backtrace
= TRUE
;
4001 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
4002 mini_debug_options
.suspend_on_native_crash
= TRUE
;
4003 else if (!strcmp (option
, "suspend-on-exception"))
4004 mini_debug_options
.suspend_on_exception
= TRUE
;
4005 else if (!strcmp (option
, "suspend-on-unhandled"))
4006 mini_debug_options
.suspend_on_unhandled
= TRUE
;
4007 else if (!strcmp (option
, "dont-free-domains"))
4008 mono_dont_free_domains
= TRUE
;
4009 else if (!strcmp (option
, "dyn-runtime-invoke"))
4010 mini_debug_options
.dyn_runtime_invoke
= TRUE
;
4011 else if (!strcmp (option
, "gdb"))
4012 mini_debug_options
.gdb
= TRUE
;
4013 else if (!strcmp (option
, "lldb"))
4014 mini_debug_options
.lldb
= TRUE
;
4015 else if (!strcmp (option
, "llvm-disable-inlining"))
4016 mini_debug_options
.llvm_disable_inlining
= TRUE
;
4017 else if (!strcmp (option
, "llvm-disable-implicit-null-checks"))
4018 mini_debug_options
.llvm_disable_implicit_null_checks
= TRUE
;
4019 else if (!strcmp (option
, "explicit-null-checks"))
4020 mini_debug_options
.explicit_null_checks
= TRUE
;
4021 else if (!strcmp (option
, "gen-seq-points"))
4022 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
4023 else if (!strcmp (option
, "gen-compact-seq-points"))
4024 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
4025 else if (!strcmp (option
, "no-compact-seq-points"))
4026 mini_debug_options
.no_seq_points_compact_data
= TRUE
;
4027 else if (!strcmp (option
, "single-imm-size"))
4028 mini_debug_options
.single_imm_size
= TRUE
;
4029 else if (!strcmp (option
, "init-stacks"))
4030 mini_debug_options
.init_stacks
= TRUE
;
4031 else if (!strcmp (option
, "casts"))
4032 mini_debug_options
.better_cast_details
= TRUE
;
4033 else if (!strcmp (option
, "soft-breakpoints"))
4034 mini_debug_options
.soft_breakpoints
= TRUE
;
4035 else if (!strcmp (option
, "check-pinvoke-callconv"))
4036 mini_debug_options
.check_pinvoke_callconv
= TRUE
;
4037 else if (!strcmp (option
, "use-fallback-tls"))
4038 mini_debug_options
.use_fallback_tls
= TRUE
;
4039 else if (!strcmp (option
, "debug-domain-unload"))
4040 mono_enable_debug_domain_unload (TRUE
);
4041 else if (!strcmp (option
, "partial-sharing"))
4042 mono_set_partial_sharing_supported (TRUE
);
4043 else if (!strcmp (option
, "align-small-structs"))
4044 mono_align_small_structs
= TRUE
;
4045 else if (!strcmp (option
, "native-debugger-break"))
4046 mini_debug_options
.native_debugger_break
= TRUE
;
4047 else if (!strcmp (option
, "disable_omit_fp"))
4048 mini_debug_options
.disable_omit_fp
= TRUE
;
4049 // This is an internal testing feature.
4050 // Every tail. encountered is required to be optimized.
4052 else if (!strcmp (option
, "test-tailcall-require"))
4053 mini_debug_options
.test_tailcall_require
= TRUE
;
4054 else if (!strcmp (option
, "verbose-gdb"))
4055 mini_debug_options
.verbose_gdb
= TRUE
;
4056 else if (!strcmp (option
, "clr-memory-model"))
4057 // FIXME Kill this debug flag
4058 mini_debug_options
.weak_memory_model
= FALSE
;
4059 else if (!strcmp (option
, "weak-memory-model"))
4060 mini_debug_options
.weak_memory_model
= TRUE
;
4061 else if (!strcmp (option
, "top-runtime-invoke-unhandled"))
4062 mini_debug_options
.top_runtime_invoke_unhandled
= TRUE
;
4063 else if (!strncmp (option
, "thread-dump-dir=", 16))
4064 mono_set_thread_dump_dir(g_strdup(option
+ 16));
4065 else if (!strncmp (option
, "aot-skip=", 9)) {
4066 mini_debug_options
.aot_skip_set
= TRUE
;
4067 mini_debug_options
.aot_skip
= atoi (option
+ 9);
4075 mini_parse_debug_options (void)
4077 char *options
= g_getenv ("MONO_DEBUG");
4078 gchar
**args
, **ptr
;
4083 args
= g_strsplit (options
, ",", -1);
4086 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
4087 const char *arg
= *ptr
;
4089 if (!mini_parse_debug_option (arg
)) {
4090 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
4091 // test-tailcall-require is also accepted but not documented.
4092 // empty string is also accepted and ignored as a consequence
4093 // of appending ",foo" without checking for empty.
4094 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");
4103 mini_get_debug_options (void)
4105 return &mini_debug_options
;
4109 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
4111 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4112 gpointer
* desc
= NULL
;
4114 if ((desc
= (gpointer
*)g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
4116 #if defined(__mono_ppc64__)
4117 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
4123 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
4131 mini_get_addr_from_ftnptr (gpointer descr
)
4133 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4134 return *(gpointer
*)descr
;
4141 register_counters (void)
4143 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
4144 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
4145 mono_counters_register ("Methods from AOT+LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot_llvm
);
4146 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
4147 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
4148 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_interp
);
4151 static void runtime_invoke_info_free (gpointer value
);
4154 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
4156 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
4157 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
4159 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
4163 class_method_pair_hash (gconstpointer data
)
4165 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
4167 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
4171 mini_create_jit_domain_info (MonoDomain
*domain
)
4173 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
4175 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4176 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4177 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
4178 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4179 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
4180 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
4181 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4182 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
4183 mono_jit_code_hash_init (&info
->interp_code_hash
);
4185 domain
->runtime_info
= info
;
4189 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
4191 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
4192 g_slist_free ((GSList
*)jlist
->list
);
4196 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
4198 GSList
*list
= (GSList
*)value
;
4199 g_slist_free (list
);
4203 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
4205 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
4206 mono_code_manager_destroy (di
->code_mp
);
4211 runtime_invoke_info_free (gpointer value
)
4213 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
4215 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4216 if (info
->dyn_call_info
)
4217 mono_arch_dyn_call_free (info
->dyn_call_info
);
4223 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
4225 g_slist_free ((GSList
*)value
);
4229 mini_free_jit_domain_info (MonoDomain
*domain
)
4231 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
4233 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
4234 g_hash_table_destroy (info
->jump_target_hash
);
4235 if (info
->jump_target_got_slot_hash
) {
4236 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
4237 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
4239 if (info
->dynamic_code_hash
) {
4240 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
4241 g_hash_table_destroy (info
->dynamic_code_hash
);
4243 g_hash_table_destroy (info
->method_code_hash
);
4244 g_hash_table_destroy (info
->jump_trampoline_hash
);
4245 g_hash_table_destroy (info
->jit_trampoline_hash
);
4246 g_hash_table_destroy (info
->delegate_trampoline_hash
);
4247 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
4248 g_hash_table_destroy (info
->mrgctx_hash
);
4249 g_hash_table_destroy (info
->method_rgctx_hash
);
4250 g_hash_table_destroy (info
->interp_method_pointer_hash
);
4251 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
4252 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
4253 g_hash_table_destroy (info
->seq_points
);
4254 g_hash_table_destroy (info
->arch_seq_points
);
4255 if (info
->agent_info
)
4256 mini_get_dbg_callbacks ()->free_domain_info (domain
);
4257 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
4258 if (info
->llvm_jit_callees
) {
4259 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
4260 g_hash_table_destroy (info
->llvm_jit_callees
);
4262 mono_internal_hash_table_destroy (&info
->interp_code_hash
);
4264 mono_llvm_free_domain_info (domain
);
4267 g_free (domain
->runtime_info
);
4268 domain
->runtime_info
= NULL
;
4273 llvm_init_inner (void)
4275 mono_llvm_init (!mono_compile_aot
);
4283 * Load and initialize LLVM support.
4284 * Return TRUE on success.
4287 mini_llvm_init (void)
4290 static gboolean llvm_inited
;
4291 static gboolean init_result
;
4293 mono_loader_lock_if_inited ();
4295 init_result
= llvm_init_inner ();
4298 mono_loader_unlock_if_inited ();
4306 mini_add_profiler_argument (const char *desc
)
4308 if (!profile_options
)
4309 profile_options
= g_ptr_array_new ();
4311 g_ptr_array_add (profile_options
, (gpointer
) g_strdup (desc
));
4315 const MonoEECallbacks
*mono_interp_callbacks_pointer
;
4318 mini_install_interp_callbacks (const MonoEECallbacks
*cbs
)
4320 mono_interp_callbacks_pointer
= cbs
;
4323 static MonoDebuggerCallbacks dbg_cbs
;
4326 mini_install_dbg_callbacks (MonoDebuggerCallbacks
*cbs
)
4328 g_assert (cbs
->version
== MONO_DBG_CALLBACKS_VERSION
);
4329 memcpy (&dbg_cbs
, cbs
, sizeof (MonoDebuggerCallbacks
));
4332 MonoDebuggerCallbacks
*
4333 mini_get_dbg_callbacks (void)
4339 mono_ee_api_version (void)
4341 return MONO_EE_API_VERSION
;
4345 mono_interp_entry_from_trampoline (gpointer ccontext
, gpointer imethod
)
4347 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext
, imethod
);
4351 mono_interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
4353 mini_get_interp_callbacks ()->to_native_trampoline (addr
, ccontext
);
4357 mini_is_interpreter_enabled (void)
4359 return mono_use_interpreter
;
4363 mono_get_runtime_build_version (void);
4366 mini_init (const char *filename
, const char *runtime_version
)
4371 MonoRuntimeCallbacks callbacks
;
4373 static const MonoThreadInfoRuntimeCallbacks ticallbacks
= {
4374 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK
, mono
)
4377 MONO_VES_INIT_BEGIN ();
4379 CHECKED_MONO_INIT ();
4381 #if defined(__linux__)
4382 if (access ("/proc/self/maps", F_OK
) != 0) {
4383 g_print ("Mono requires /proc to be mounted.\n");
4388 mono_debugger_agent_stub_init ();
4390 mono_debugger_agent_init ();
4394 mini_get_dbg_callbacks ()->parse_options (sdb_options
);
4396 mono_interp_stub_init ();
4397 #ifndef DISABLE_INTERPRETER
4398 if (mono_use_interpreter
)
4399 mono_ee_interp_init (mono_interp_opts_string
);
4402 mono_os_mutex_init_recursive (&jit_mutex
);
4404 mono_cross_helpers_run ();
4406 mono_counters_init ();
4410 mini_jit_init_job_control ();
4412 /* Happens when using the embedding interface */
4413 if (!default_opt_set
)
4414 default_opt
= mono_parse_default_optimizations (NULL
);
4416 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4418 mono_set_generic_sharing_vt_supported (TRUE
);
4421 mono_set_generic_sharing_vt_supported (TRUE
);
4424 mono_tls_init_runtime_keys ();
4426 if (!global_codeman
)
4427 global_codeman
= mono_code_manager_new ();
4429 memset (&callbacks
, 0, sizeof (callbacks
));
4430 callbacks
.create_ftnptr
= mini_create_ftnptr
;
4431 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
4432 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
4433 callbacks
.get_runtime_build_version
= mono_get_runtime_build_version
;
4434 callbacks
.set_cast_details
= mono_set_cast_details
;
4435 callbacks
.debug_log
= mini_get_dbg_callbacks ()->debug_log
;
4436 callbacks
.debug_log_is_enabled
= mini_get_dbg_callbacks ()->debug_log_is_enabled
;
4437 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
4438 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
4439 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
4440 callbacks
.init_delegate
= mini_init_delegate
;
4441 #define JIT_INVOKE_WORKS
4442 #ifdef JIT_INVOKE_WORKS
4443 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
4445 #define JIT_TRAMPOLINES_WORK
4446 #ifdef JIT_TRAMPOLINES_WORK
4447 callbacks
.compile_method
= mono_jit_compile_method
;
4448 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
4449 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
4450 callbacks
.free_method
= mono_jit_free_method
;
4451 #ifndef DISABLE_REMOTING
4452 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
4455 #ifndef DISABLE_REMOTING
4456 if (mono_use_interpreter
)
4457 callbacks
.interp_get_remoting_invoke
= mini_get_interp_callbacks ()->get_remoting_invoke
;
4459 callbacks
.is_interpreter_enabled
= mini_is_interpreter_enabled
;
4460 callbacks
.get_weak_field_indexes
= mono_aot_get_weak_field_indexes
;
4462 #ifndef DISABLE_CRASH_REPORTING
4463 callbacks
.install_state_summarizer
= mini_register_sigterm_handler
;
4465 #ifdef ENABLE_METADATA_UPDATE
4466 callbacks
.metadata_update_init
= mini_metadata_update_init
;
4467 callbacks
.metadata_update_published
= mini_invalidate_transformed_interp_methods
;
4470 mono_install_callbacks (&callbacks
);
4473 mono_w32handle_init ();
4476 mono_thread_info_runtime_init (&ticallbacks
);
4478 if (g_hasenv ("MONO_DEBUG")) {
4479 mini_parse_debug_options ();
4482 mono_code_manager_init ();
4484 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4486 static const MonoCodeManagerCallbacks code_manager_callbacks
= {
4488 #undef MONO_CODE_MANAGER_CALLBACK
4489 #define MONO_CODE_MANAGER_CALLBACK(ret, name, sig) mono_arch_code_ ## name,
4490 MONO_CODE_MANAGER_CALLBACKS
4494 mono_code_manager_install_callbacks (&code_manager_callbacks
);
4499 mono_arch_cpu_init ();
4503 mono_unwind_init ();
4505 if (mini_debug_options
.lldb
|| g_hasenv ("MONO_LLDB")) {
4506 mono_lldb_init ("");
4507 mono_dont_free_domains
= TRUE
;
4510 #ifdef XDEBUG_ENABLED
4511 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
4513 mono_xdebug_init (mono_xdebug
);
4514 g_free (mono_xdebug
);
4515 /* So methods for multiple domains don't have the same address */
4516 mono_dont_free_domains
= TRUE
;
4517 mono_using_xdebug
= TRUE
;
4518 } else if (mini_debug_options
.gdb
) {
4519 mono_xdebug_init ((char*)"gdb");
4520 mono_dont_free_domains
= TRUE
;
4521 mono_using_xdebug
= TRUE
;
4527 mono_llvm_init (!mono_compile_aot
);
4530 mono_trampolines_init ();
4532 if (default_opt
& MONO_OPT_AOT
)
4535 mini_get_dbg_callbacks ()->init ();
4538 mono_wasm_debugger_init ();
4541 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4542 mono_set_generic_sharing_supported (TRUE
);
4545 mono_thread_info_signals_init ();
4547 mono_init_native_crash_info ();
4549 #ifndef MONO_CROSS_COMPILE
4550 mono_runtime_install_handlers ();
4552 mono_threads_install_cleanup (mini_thread_cleanup
);
4554 #ifdef JIT_TRAMPOLINES_WORK
4555 mono_install_create_domain_hook (mini_create_jit_domain_info
);
4556 mono_install_free_domain_hook (mini_free_jit_domain_info
);
4558 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
4559 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
4560 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
4562 mono_profiler_state
.context_enable
= mini_profiler_context_enable
;
4563 mono_profiler_state
.context_get_this
= mini_profiler_context_get_this
;
4564 mono_profiler_state
.context_get_argument
= mini_profiler_context_get_argument
;
4565 mono_profiler_state
.context_get_local
= mini_profiler_context_get_local
;
4566 mono_profiler_state
.context_get_result
= mini_profiler_context_get_result
;
4567 mono_profiler_state
.context_free_buffer
= mini_profiler_context_free_buffer
;
4569 if (g_hasenv ("MONO_PROFILE")) {
4570 gchar
*profile_env
= g_getenv ("MONO_PROFILE");
4571 mini_add_profiler_argument (profile_env
);
4572 g_free (profile_env
);
4575 if (profile_options
)
4576 for (guint i
= 0; i
< profile_options
->len
; i
++)
4577 mono_profiler_load ((const char *) g_ptr_array_index (profile_options
, i
));
4579 mono_profiler_started ();
4581 if (mini_debug_options
.collect_pagefault_stats
)
4582 mono_aot_set_make_unreadable (TRUE
);
4584 if (runtime_version
)
4585 domain
= mono_init_version (filename
, runtime_version
);
4587 domain
= mono_init_from_assembly (filename
, filename
);
4589 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
4590 if (mono_compile_aot
)
4591 ds_server_disable ();
4596 if (mono_aot_only
) {
4597 /* This helps catch code allocation requests */
4598 mono_code_manager_set_read_only (mono_domain_ambient_memory_manager (domain
)->code_mp
);
4599 mono_marshal_use_aot_wrappers (TRUE
);
4602 if (mono_llvm_only
) {
4603 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline
);
4604 mono_set_always_build_imt_trampolines (TRUE
);
4605 } else if (mono_aot_only
) {
4606 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
4608 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
4611 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4612 mono_arch_finish_init ();
4614 /* This must come after mono_init () in the aot-only case */
4615 mono_exceptions_init ();
4617 /* This should come after mono_init () too */
4620 mono_create_icall_signatures ();
4622 register_counters ();
4624 #define JIT_CALLS_WORK
4625 #ifdef JIT_CALLS_WORK
4626 /* Needs to be called here since register_jit_icall depends on it */
4627 mono_marshal_init ();
4629 mono_arch_register_lowlevel_calls ();
4633 mono_generic_sharing_init ();
4636 #ifdef MONO_ARCH_SIMD_INTRINSICS
4637 mono_simd_intrinsics_init ();
4640 mono_tasklets_init ();
4642 register_trampolines (domain
);
4644 if (mono_compile_aot
)
4646 * Avoid running managed code when AOT compiling, since the platform
4647 * might only support aot-only execution.
4649 mono_runtime_set_no_exec (TRUE
);
4651 mono_mem_account_register_counters ();
4653 #define JIT_RUNTIME_WORKS
4654 #ifdef JIT_RUNTIME_WORKS
4655 mono_install_runtime_cleanup (runtime_cleanup
);
4656 mono_runtime_init_checked (domain
, (MonoThreadStartCB
)mono_thread_start_cb
, mono_thread_attach_cb
, error
);
4657 mono_error_assert_ok (error
);
4658 mono_thread_internal_attach (domain
);
4659 MONO_PROFILER_RAISE (thread_name
, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4661 mono_threads_set_runtime_startup_finished ();
4663 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
4667 #ifdef ENABLE_EXPERIMENT_TIERED
4668 if (!mono_compile_aot
) {
4669 /* create compilation thread in background */
4670 mini_tiered_init ();
4674 if (mono_profiler_sampling_enabled ())
4675 mono_runtime_setup_stat_profiler ();
4677 MONO_PROFILER_RAISE (runtime_initialized
, ());
4679 MONO_VES_INIT_END ();
4685 register_icalls (void)
4687 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4688 ves_icall_get_frame_info
);
4689 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4690 ves_icall_get_trace
);
4691 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4692 mono_runtime_install_handlers
);
4693 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4694 mono_runtime_cleanup_handlers
);
4696 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4697 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4698 mini_get_dbg_callbacks ()->unhandled_exception
);
4702 * It's important that we pass `TRUE` as the last argument here, as
4703 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4704 * *did* emit a wrapper, we'd be looking at infinite recursion since
4705 * the wrapper would call the icall which would call the wrapper and
4708 register_icall (mono_profiler_raise_method_enter
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4709 register_icall (mono_profiler_raise_method_leave
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4710 register_icall (mono_profiler_raise_method_tail_call
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4711 register_icall (mono_profiler_raise_exception_clause
, mono_icall_sig_void_ptr_int_int_object
, TRUE
);
4713 register_icall (mono_trace_enter_method
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4714 register_icall (mono_trace_leave_method
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4715 register_icall (mono_trace_tail_method
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4716 g_assert (mono_get_lmf_addr
== mono_tls_get_lmf_addr
);
4717 register_icall (mono_jit_set_domain
, mono_icall_sig_void_ptr
, TRUE
);
4718 register_icall (mono_domain_get
, mono_icall_sig_ptr
, TRUE
);
4720 register_icall (mono_llvm_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4721 register_icall (mono_llvm_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4722 register_icall (mono_llvm_resume_exception
, mono_icall_sig_void
, TRUE
);
4723 register_icall (mono_llvm_match_exception
, mono_icall_sig_int_ptr_int_int_ptr_object
, TRUE
);
4724 register_icall (mono_llvm_clear_exception
, NULL
, TRUE
);
4725 register_icall (mono_llvm_load_exception
, mono_icall_sig_object
, TRUE
);
4726 register_icall (mono_llvm_throw_corlib_exception
, mono_icall_sig_void_int
, TRUE
);
4727 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4728 register_icall (mono_llvm_set_unhandled_exception_handler
, NULL
, TRUE
);
4730 // FIXME: This is broken
4732 register_icall (mono_debug_personality
, mono_icall_sig_int_int_int_ptr_ptr_ptr
, TRUE
);
4736 if (!mono_llvm_only
) {
4737 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4738 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4739 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception
, mono_icall_sig_void_ptr
, TRUE
);
4741 register_icall (mono_thread_get_undeniable_exception
, mono_icall_sig_object
, FALSE
);
4742 register_icall (ves_icall_thread_finish_async_abort
, mono_icall_sig_void
, FALSE
);
4743 register_icall (mono_thread_interruption_checkpoint
, mono_icall_sig_object
, FALSE
);
4744 register_icall (mono_thread_force_interruption_checkpoint_noraise
, mono_icall_sig_object
, FALSE
);
4746 register_icall (mono_threads_state_poll
, mono_icall_sig_void
, FALSE
);
4748 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4749 register_opcode_emulation (OP_LMUL
, __emul_lmul
, mono_icall_sig_long_long_long
, mono_llmult
, FALSE
);
4750 register_opcode_emulation (OP_LDIV
, __emul_ldiv
, mono_icall_sig_long_long_long
, mono_lldiv
, FALSE
);
4751 register_opcode_emulation (OP_LDIV_UN
, __emul_ldiv_un
, mono_icall_sig_long_long_long
, mono_lldiv_un
, FALSE
);
4752 register_opcode_emulation (OP_LREM
, __emul_lrem
, mono_icall_sig_long_long_long
, mono_llrem
, FALSE
);
4753 register_opcode_emulation (OP_LREM_UN
, __emul_lrem_un
, mono_icall_sig_long_long_long
, mono_llrem_un
, FALSE
);
4755 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4756 register_opcode_emulation (OP_LMUL_OVF_UN
, __emul_lmul_ovf_un
, mono_icall_sig_long_long_long
, mono_llmult_ovf_un
, FALSE
);
4757 register_opcode_emulation (OP_LMUL_OVF
, __emul_lmul_ovf
, mono_icall_sig_long_long_long
, mono_llmult_ovf
, FALSE
);
4760 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4761 register_opcode_emulation (OP_LSHL
, __emul_lshl
, mono_icall_sig_long_long_int32
, mono_lshl
, TRUE
);
4762 register_opcode_emulation (OP_LSHR
, __emul_lshr
, mono_icall_sig_long_long_int32
, mono_lshr
, TRUE
);
4763 register_opcode_emulation (OP_LSHR_UN
, __emul_lshr_un
, mono_icall_sig_long_long_int32
, mono_lshr_un
, TRUE
);
4766 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4767 register_opcode_emulation (OP_IDIV
, __emul_op_idiv
, mono_icall_sig_int32_int32_int32
, mono_idiv
, FALSE
);
4768 register_opcode_emulation (OP_IDIV_UN
, __emul_op_idiv_un
, mono_icall_sig_int32_int32_int32
, mono_idiv_un
, FALSE
);
4769 register_opcode_emulation (OP_IREM
, __emul_op_irem
, mono_icall_sig_int32_int32_int32
, mono_irem
, FALSE
);
4770 register_opcode_emulation (OP_IREM_UN
, __emul_op_irem_un
, mono_icall_sig_int32_int32_int32
, mono_irem_un
, FALSE
);
4773 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4774 register_opcode_emulation (OP_IMUL
, __emul_op_imul
, mono_icall_sig_int32_int32_int32
, mono_imul
, TRUE
);
4777 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4778 register_opcode_emulation (OP_IMUL_OVF
, __emul_op_imul_ovf
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf
, FALSE
);
4779 register_opcode_emulation (OP_IMUL_OVF_UN
, __emul_op_imul_ovf_un
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf_un
, FALSE
);
4782 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4783 register_opcode_emulation (OP_FDIV
, __emul_fdiv
, mono_icall_sig_double_double_double
, mono_fdiv
, FALSE
);
4786 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4787 register_opcode_emulation (OP_FCONV_TO_U8
, __emul_fconv_to_u8
, mono_icall_sig_ulong_double
, mono_fconv_u8_2
, FALSE
);
4788 register_opcode_emulation (OP_RCONV_TO_U8
, __emul_rconv_to_u8
, mono_icall_sig_ulong_float
, mono_rconv_u8
, FALSE
);
4790 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4791 register_opcode_emulation (OP_FCONV_TO_U4
, __emul_fconv_to_u4
, mono_icall_sig_uint32_double
, mono_fconv_u4_2
, FALSE
);
4792 register_opcode_emulation (OP_RCONV_TO_U4
, __emul_rconv_to_u4
, mono_icall_sig_uint32_float
, mono_rconv_u4
, FALSE
);
4794 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, __emul_fconv_to_ovf_i8
, mono_icall_sig_long_double
, mono_fconv_ovf_i8
, FALSE
);
4795 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, __emul_fconv_to_ovf_u8
, mono_icall_sig_ulong_double
, mono_fconv_ovf_u8
, FALSE
);
4796 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, __emul_rconv_to_ovf_i8
, mono_icall_sig_long_float
, mono_rconv_ovf_i8
, FALSE
);
4797 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, __emul_rconv_to_ovf_u8
, mono_icall_sig_ulong_float
, mono_rconv_ovf_u8
, FALSE
);
4799 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4800 register_opcode_emulation (OP_FCONV_TO_I8
, __emul_fconv_to_i8
, mono_icall_sig_long_double
, mono_fconv_i8
, FALSE
);
4801 register_opcode_emulation (OP_RCONV_TO_I8
, __emul_rconv_to_i8
, mono_icall_sig_long_float
, mono_rconv_i8
, FALSE
);
4804 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4805 register_opcode_emulation (OP_ICONV_TO_R_UN
, __emul_iconv_to_r_un
, mono_icall_sig_double_int32
, mono_conv_to_r8_un
, FALSE
);
4807 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4808 register_opcode_emulation (OP_LCONV_TO_R8
, __emul_lconv_to_r8
, mono_icall_sig_double_long
, mono_lconv_to_r8
, FALSE
);
4810 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4811 register_opcode_emulation (OP_LCONV_TO_R4
, __emul_lconv_to_r4
, mono_icall_sig_float_long
, mono_lconv_to_r4
, FALSE
);
4813 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4814 register_opcode_emulation (OP_LCONV_TO_R_UN
, __emul_lconv_to_r8_un
, mono_icall_sig_double_long
, mono_lconv_to_r8_un
, FALSE
);
4816 #ifdef MONO_ARCH_EMULATE_FREM
4817 register_opcode_emulation (OP_FREM
, __emul_frem
, mono_icall_sig_double_double_double
, mono_fmod
, FALSE
);
4818 register_opcode_emulation (OP_RREM
, __emul_rrem
, mono_icall_sig_float_float_float
, fmodf
, FALSE
);
4821 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4822 if (mono_arch_is_soft_float ()) {
4823 register_opcode_emulation (OP_FSUB
, __emul_fsub
, mono_icall_sig_double_double_double
, mono_fsub
, FALSE
);
4824 register_opcode_emulation (OP_FADD
, __emul_fadd
, mono_icall_sig_double_double_double
, mono_fadd
, FALSE
);
4825 register_opcode_emulation (OP_FMUL
, __emul_fmul
, mono_icall_sig_double_double_double
, mono_fmul
, FALSE
);
4826 register_opcode_emulation (OP_FNEG
, __emul_fneg
, mono_icall_sig_double_double
, mono_fneg
, FALSE
);
4827 register_opcode_emulation (OP_ICONV_TO_R8
, __emul_iconv_to_r8
, mono_icall_sig_double_int32
, mono_conv_to_r8
, FALSE
);
4828 register_opcode_emulation (OP_ICONV_TO_R4
, __emul_iconv_to_r4
, mono_icall_sig_double_int32
, mono_conv_to_r4
, FALSE
);
4829 register_opcode_emulation (OP_FCONV_TO_R4
, __emul_fconv_to_r4
, mono_icall_sig_double_double
, mono_fconv_r4
, FALSE
);
4830 register_opcode_emulation (OP_FCONV_TO_I1
, __emul_fconv_to_i1
, mono_icall_sig_int8_double
, mono_fconv_i1
, FALSE
);
4831 register_opcode_emulation (OP_FCONV_TO_I2
, __emul_fconv_to_i2
, mono_icall_sig_int16_double
, mono_fconv_i2
, FALSE
);
4832 register_opcode_emulation (OP_FCONV_TO_I4
, __emul_fconv_to_i4
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4833 register_opcode_emulation (OP_FCONV_TO_U1
, __emul_fconv_to_u1
, mono_icall_sig_uint8_double
, mono_fconv_u1
, FALSE
);
4834 register_opcode_emulation (OP_FCONV_TO_U2
, __emul_fconv_to_u2
, mono_icall_sig_uint16_double
, mono_fconv_u2
, FALSE
);
4836 #if TARGET_SIZEOF_VOID_P == 4
4837 register_opcode_emulation (OP_FCONV_TO_I
, __emul_fconv_to_i
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4840 register_opcode_emulation (OP_FBEQ
, __emul_fcmp_eq
, mono_icall_sig_uint32_double_double
, mono_fcmp_eq
, FALSE
);
4841 register_opcode_emulation (OP_FBLT
, __emul_fcmp_lt
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt
, FALSE
);
4842 register_opcode_emulation (OP_FBGT
, __emul_fcmp_gt
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt
, FALSE
);
4843 register_opcode_emulation (OP_FBLE
, __emul_fcmp_le
, mono_icall_sig_uint32_double_double
, mono_fcmp_le
, FALSE
);
4844 register_opcode_emulation (OP_FBGE
, __emul_fcmp_ge
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge
, FALSE
);
4845 register_opcode_emulation (OP_FBNE_UN
, __emul_fcmp_ne_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ne_un
, FALSE
);
4846 register_opcode_emulation (OP_FBLT_UN
, __emul_fcmp_lt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt_un
, FALSE
);
4847 register_opcode_emulation (OP_FBGT_UN
, __emul_fcmp_gt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt_un
, FALSE
);
4848 register_opcode_emulation (OP_FBLE_UN
, __emul_fcmp_le_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_le_un
, FALSE
);
4849 register_opcode_emulation (OP_FBGE_UN
, __emul_fcmp_ge_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge_un
, FALSE
);
4851 register_opcode_emulation (OP_FCEQ
, __emul_fcmp_ceq
, mono_icall_sig_uint32_double_double
, mono_fceq
, FALSE
);
4852 register_opcode_emulation (OP_FCGT
, __emul_fcmp_cgt
, mono_icall_sig_uint32_double_double
, mono_fcgt
, FALSE
);
4853 register_opcode_emulation (OP_FCGT_UN
, __emul_fcmp_cgt_un
, mono_icall_sig_uint32_double_double
, mono_fcgt_un
, FALSE
);
4854 register_opcode_emulation (OP_FCLT
, __emul_fcmp_clt
, mono_icall_sig_uint32_double_double
, mono_fclt
, FALSE
);
4855 register_opcode_emulation (OP_FCLT_UN
, __emul_fcmp_clt_un
, mono_icall_sig_uint32_double_double
, mono_fclt_un
, FALSE
);
4857 register_icall (mono_fload_r4
, mono_icall_sig_double_ptr
, FALSE
);
4858 register_icall (mono_fstore_r4
, mono_icall_sig_void_double_ptr
, FALSE
);
4859 register_icall (mono_fload_r4_arg
, mono_icall_sig_uint32_double
, FALSE
);
4860 register_icall (mono_isfinite_double
, mono_icall_sig_int32_double
, FALSE
);
4863 register_icall (mono_ckfinite
, mono_icall_sig_double_double
, FALSE
);
4865 #ifdef COMPRESSED_INTERFACE_BITMAP
4866 register_icall (mono_class_interface_match
, mono_icall_sig_uint32_ptr_int32
, TRUE
);
4869 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4870 #if SIZEOF_REGISTER == 4
4871 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_uint32_double
, mono_fconv_u4
, TRUE
);
4873 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_ulong_double
, mono_fconv_u8
, TRUE
);
4876 /* other jit icalls */
4877 register_icall (ves_icall_mono_delegate_ctor
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4878 register_icall (ves_icall_mono_delegate_ctor_interp
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4879 register_icall (mono_class_static_field_address
,
4880 mono_icall_sig_ptr_ptr_ptr
, FALSE
);
4881 register_icall (mono_ldtoken_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4882 register_icall (mono_ldtoken_wrapper_generic_shared
,
4883 mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4884 register_icall (mono_get_special_static_data
, mono_icall_sig_ptr_int
, FALSE
);
4885 register_icall (ves_icall_mono_ldstr
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4886 register_icall (mono_helper_stelem_ref_check
, mono_icall_sig_void_object_object
, FALSE
);
4887 register_icall (ves_icall_object_new
, mono_icall_sig_object_ptr_ptr
, FALSE
);
4888 register_icall (ves_icall_object_new_specific
, mono_icall_sig_object_ptr
, FALSE
);
4889 register_icall (ves_icall_array_new
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4890 register_icall (ves_icall_array_new_specific
, mono_icall_sig_object_ptr_int32
, FALSE
);
4891 register_icall (ves_icall_runtime_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4892 register_icall (mono_ldftn
, mono_icall_sig_ptr_ptr
, FALSE
);
4893 register_icall (mono_ldvirtfn
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4894 register_icall (mono_ldvirtfn_gshared
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4895 register_icall (mono_helper_compile_generic_method
, mono_icall_sig_ptr_object_ptr_ptr
, FALSE
);
4896 register_icall (mono_helper_ldstr
, mono_icall_sig_object_ptr_int
, FALSE
);
4897 register_icall (mono_helper_ldstr_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4898 register_icall (mono_helper_newobj_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4899 register_icall (mono_value_copy_internal
, mono_icall_sig_void_ptr_ptr_ptr
, FALSE
);
4900 register_icall (mono_object_castclass_unbox
, mono_icall_sig_object_object_ptr
, FALSE
);
4901 register_icall (mono_break
, NULL
, TRUE
);
4902 register_icall (mono_create_corlib_exception_0
, mono_icall_sig_object_int
, TRUE
);
4903 register_icall (mono_create_corlib_exception_1
, mono_icall_sig_object_int_object
, TRUE
);
4904 register_icall (mono_create_corlib_exception_2
, mono_icall_sig_object_int_object_object
, TRUE
);
4905 register_icall (mono_array_new_1
, mono_icall_sig_object_ptr_int
, FALSE
);
4906 register_icall (mono_array_new_2
, mono_icall_sig_object_ptr_int_int
, FALSE
);
4907 register_icall (mono_array_new_3
, mono_icall_sig_object_ptr_int_int_int
, FALSE
);
4908 register_icall (mono_array_new_4
, mono_icall_sig_object_ptr_int_int_int_int
, FALSE
);
4909 register_icall (mono_array_new_n_icall
, mono_icall_sig_object_ptr_int_ptr
, FALSE
);
4910 register_icall (mono_get_native_calli_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4911 register_icall (mono_resume_unwind
, mono_icall_sig_void_ptr
, TRUE
);
4912 register_icall (mono_gsharedvt_constrained_call
, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr
, FALSE
);
4913 register_icall (mono_gsharedvt_value_copy
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4915 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4916 MonoRangeCopyFunction
const mono_gc_wbarrier_range_copy
= mono_gc_get_range_copy_func ();
4917 register_icall_no_wrapper (mono_gc_wbarrier_range_copy
, mono_icall_sig_void_ptr_ptr_int
);
4919 register_icall (mono_object_castclass_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4920 register_icall (mono_object_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4921 register_icall (mono_generic_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4922 register_icall (mono_fill_class_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4923 register_icall (mono_fill_method_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4925 register_dyn_icall (mini_get_dbg_callbacks ()->user_break
, mono_debugger_agent_user_break
, mono_icall_sig_void
, FALSE
);
4927 register_icall (mini_llvm_init_method
, mono_icall_sig_void_ptr_ptr_ptr_ptr
, TRUE
);
4928 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4929 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4930 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4931 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4932 /* This needs a wrapper so it can have a preserveall cconv */
4933 register_icall (mini_llvmonly_init_vtable_slot
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4934 register_icall (mini_llvmonly_init_delegate
, mono_icall_sig_void_object
, TRUE
);
4935 register_icall (mini_llvmonly_init_delegate_virtual
, mono_icall_sig_void_object_object_ptr
, TRUE
);
4936 register_icall (mini_llvmonly_throw_nullref_exception
, mono_icall_sig_void
, TRUE
);
4937 register_icall (mini_llvmonly_throw_aot_failed_exception
, mono_icall_sig_void_ptr
, TRUE
);
4938 register_icall (mini_llvmonly_pop_lmf
, mono_icall_sig_void_ptr
, TRUE
);
4939 register_icall (mini_llvmonly_get_interp_entry
, mono_icall_sig_ptr_ptr
, TRUE
);
4941 register_icall (mono_get_assembly_object
, mono_icall_sig_object_ptr
, TRUE
);
4942 register_icall (mono_get_method_object
, mono_icall_sig_object_ptr
, TRUE
);
4943 register_icall (mono_throw_method_access
, mono_icall_sig_void_ptr_ptr
, FALSE
);
4944 register_icall (mono_throw_bad_image
, mono_icall_sig_void
, FALSE
);
4945 register_icall (mono_throw_not_supported
, mono_icall_sig_void
, FALSE
);
4946 register_icall (mono_throw_invalid_program
, mono_icall_sig_void_ptr
, FALSE
);
4947 register_icall_no_wrapper (mono_dummy_jit_icall
, mono_icall_sig_void
);
4949 register_icall_with_wrapper (mono_monitor_enter_internal
, mono_icall_sig_int32_obj
);
4950 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, mono_icall_sig_void_obj_ptr
);
4951 register_icall_no_wrapper (mono_monitor_enter_fast
, mono_icall_sig_int_obj
);
4952 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, mono_icall_sig_int_obj_ptr
);
4955 register_icall (pthread_getspecific
, mono_icall_sig_ptr_ptr
, TRUE
);
4957 /* Register tls icalls */
4958 register_icall_no_wrapper (mono_tls_get_thread_extern
, mono_icall_sig_ptr
);
4959 register_icall_no_wrapper (mono_tls_get_jit_tls_extern
, mono_icall_sig_ptr
);
4960 register_icall_no_wrapper (mono_tls_get_domain_extern
, mono_icall_sig_ptr
);
4961 register_icall_no_wrapper (mono_tls_get_sgen_thread_info_extern
, mono_icall_sig_ptr
);
4962 register_icall_no_wrapper (mono_tls_get_lmf_addr_extern
, mono_icall_sig_ptr
);
4964 register_icall_no_wrapper (mono_interp_entry_from_trampoline
, mono_icall_sig_void_ptr_ptr
);
4965 register_icall_no_wrapper (mono_interp_to_native_trampoline
, mono_icall_sig_void_ptr_ptr
);
4967 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4968 mono_arch_register_icall ();
4972 MonoJitStats mono_jit_stats
= {0};
4975 * Counters of mono_stats and mono_jit_stats can be read without locking during shutdown.
4976 * For all other contexts, assumes that the domain lock is held.
4977 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4979 MONO_NO_SANITIZE_THREAD
4981 mono_runtime_print_stats (void)
4983 if (mono_jit_stats
.enabled
) {
4984 g_print ("Mono Jit statistics\n");
4985 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/ 100.0,
4986 mono_jit_stats
.max_ratio_method
);
4987 g_print ("Biggest method: %" G_GINT32_FORMAT
" (%s)\n", mono_jit_stats
.biggest_method_size
,
4988 mono_jit_stats
.biggest_method
);
4990 g_print ("Delegates created: %" G_GINT32_FORMAT
"\n", mono_stats
.delegate_creations
);
4991 g_print ("Initialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.initialized_class_count
);
4992 g_print ("Used classes: %" G_GINT32_FORMAT
"\n", mono_stats
.used_class_count
);
4993 g_print ("Generic vtables: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_vtable_count
);
4994 g_print ("Methods: %" G_GINT32_FORMAT
"\n", mono_stats
.method_count
);
4995 g_print ("Static data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_static_data_size
);
4996 g_print ("VTable data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_vtable_size
);
4997 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4999 g_print ("\nInitialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_class_count
);
5000 g_print ("Inflated types: %" G_GINT32_FORMAT
"\n", mono_stats
.inflated_type_count
);
5001 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
5003 g_print ("Sharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_sharable_methods
);
5004 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_unsharable_methods
);
5005 g_print ("Shared generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_shared_methods
);
5006 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.gsharedvt_methods
);
5008 g_print ("IMT tables size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_tables_size
);
5009 g_print ("IMT number of tables: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_tables
);
5010 g_print ("IMT number of methods: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_methods
);
5011 g_print ("IMT used slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_used_slots
);
5012 g_print ("IMT colliding slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_slots_with_collisions
);
5013 g_print ("IMT max collisions: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_max_collisions_in_slot
);
5014 g_print ("IMT methods at max col: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_method_count_when_max_collisions
);
5015 g_print ("IMT trampolines size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_trampolines_size
);
5017 g_print ("JIT info table inserts: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_insert_count
);
5018 g_print ("JIT info table removes: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_remove_count
);
5019 g_print ("JIT info table lookups: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_lookup_count
);
5021 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, NULL
);
5027 jit_stats_cleanup (void)
5029 g_free (mono_jit_stats
.max_ratio_method
);
5030 mono_jit_stats
.max_ratio_method
= NULL
;
5031 g_free (mono_jit_stats
.biggest_method
);
5032 mono_jit_stats
.biggest_method
= NULL
;
5036 runtime_cleanup (MonoDomain
*domain
, gpointer user_data
)
5038 mini_cleanup (domain
);
5041 #ifdef DISABLE_CLEANUP
5043 mini_cleanup (MonoDomain
*domain
)
5045 if (mono_stats
.enabled
)
5046 g_printf ("Printing runtime stats at shutdown\n");
5047 mono_runtime_print_stats ();
5048 jit_stats_cleanup ();
5049 mono_jit_dump_cleanup ();
5050 mini_get_interp_callbacks ()->cleanup ();
5051 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
5053 ds_server_shutdown ();
5058 mini_cleanup (MonoDomain
*domain
)
5060 if (mono_stats
.enabled
)
5061 g_printf ("Printing runtime stats at shutdown\n");
5062 if (mono_profiler_sampling_enabled ())
5063 mono_runtime_shutdown_stat_profiler ();
5065 MONO_PROFILER_RAISE (runtime_shutdown_begin
, ());
5068 mono_cominterop_release_all_rcws ();
5071 #ifndef MONO_CROSS_COMPILE
5073 * mono_domain_finalize () needs to be called early since it needs the
5074 * execution engine still fully working (it may invoke managed finalizers).
5076 mono_domain_finalize (domain
, 2000);
5079 /* This accesses metadata so needs to be called before runtime shutdown */
5080 mono_runtime_print_stats ();
5081 jit_stats_cleanup ();
5083 #ifndef MONO_CROSS_COMPILE
5084 mono_runtime_cleanup (domain
);
5087 mono_threadpool_cleanup ();
5089 MONO_PROFILER_RAISE (runtime_shutdown_end
, ());
5091 mono_profiler_cleanup ();
5093 if (profile_options
) {
5094 for (guint i
= 0; i
< profile_options
->len
; ++i
)
5095 g_free (g_ptr_array_index (profile_options
, i
));
5096 g_ptr_array_free (profile_options
, TRUE
);
5099 mono_icall_cleanup ();
5101 mono_runtime_cleanup_handlers ();
5103 #ifndef MONO_CROSS_COMPILE
5104 mono_domain_free (domain
, TRUE
);
5106 free_jit_tls_data (mono_tls_get_jit_tls ());
5110 mono_llvm_cleanup ();
5113 mono_aot_cleanup ();
5115 mono_trampolines_cleanup ();
5117 mono_unwind_cleanup ();
5119 mono_code_manager_destroy (global_codeman
);
5120 g_free (vtable_trampolines
);
5122 mini_jit_cleanup ();
5124 mini_get_interp_callbacks ()->cleanup ();
5126 mono_tramp_info_cleanup ();
5128 mono_arch_cleanup ();
5130 mono_generic_sharing_cleanup ();
5132 mono_cleanup_native_crash_info ();
5136 mono_trace_cleanup ();
5138 if (mono_inject_async_exc_method
)
5139 mono_method_desc_free (mono_inject_async_exc_method
);
5141 mono_tls_free_keys ();
5143 mono_os_mutex_destroy (&jit_mutex
);
5145 mono_code_manager_cleanup ();
5148 mono_w32handle_cleanup ();
5154 mono_set_defaults (int verbose_level
, guint32 opts
)
5156 mini_verbose
= verbose_level
;
5157 mono_set_optimizations (opts
);
5161 mono_disable_optimizations (guint32 opts
)
5163 default_opt
&= ~opts
;
5167 mono_set_optimizations (guint32 opts
)
5169 if (opts
& MONO_OPT_AGGRESSIVE_INLINING
)
5170 opts
|= MONO_OPT_INLINE
;
5173 default_opt_set
= TRUE
;
5174 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
5175 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
5178 mono_set_generic_sharing_vt_supported (TRUE
);
5183 mono_set_verbose_level (guint32 level
)
5185 mini_verbose
= level
;
5189 mono_get_runtime_build_version (void)
5191 return FULL_VERSION
;
5195 * mono_get_runtime_build_info:
5196 * The returned string is owned by the caller. The returned string
5197 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
5198 * \returns the runtime version + build date in string format.
5201 mono_get_runtime_build_info (void)
5203 if (mono_build_date
)
5204 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
5206 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
5210 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
5212 GHashTable
*assemblies
= (GHashTable
*)user_data
;
5213 MonoImage
*image
= mono_assembly_get_image_internal (ass
);
5214 MonoMethod
*method
, *invoke
;
5217 if (g_hash_table_lookup (assemblies
, ass
))
5220 g_hash_table_insert (assemblies
, ass
, ass
);
5222 if (mini_verbose
> 0)
5223 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
5225 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
5228 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, error
);
5230 mono_error_cleanup (error
); /* FIXME don't swallow the error */
5233 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
5235 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
5239 if (mini_verbose
> 1) {
5240 char * desc
= mono_method_full_name (method
, TRUE
);
5241 g_print ("Compiling %d %s\n", count
, desc
);
5244 mono_compile_method_checked (method
, error
);
5245 if (!is_ok (error
)) {
5246 mono_error_cleanup (error
); /* FIXME don't swallow the error */
5249 if (strcmp (method
->name
, "Finalize") == 0) {
5250 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
5251 mono_compile_method_checked (invoke
, error
);
5252 mono_error_assert_ok (error
);
5254 #ifndef DISABLE_REMOTING
5255 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature_internal (method
)->hasthis
) {
5256 invoke
= mono_marshal_get_remoting_invoke_with_check (method
, error
);
5257 mono_error_assert_ok (error
);
5258 mono_compile_method_checked (invoke
, error
);
5259 mono_error_assert_ok (error
);
5264 /* Load and precompile referenced assemblies as well */
5265 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
5266 mono_assembly_load_reference (image
, i
);
5267 if (image
->references
[i
])
5268 mono_precompile_assembly (image
->references
[i
], assemblies
);
5272 void mono_precompile_assemblies ()
5274 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
5276 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
5278 g_hash_table_destroy (assemblies
);
5283 * Have to export this for AOT.
5286 mono_personality (void)
5289 g_assert_not_reached ();
5292 static MonoBreakPolicy
5293 always_insert_breakpoint (MonoMethod
*method
)
5295 return MONO_BREAK_POLICY_ALWAYS
;
5298 static MonoBreakPolicyFunc break_policy_func
= always_insert_breakpoint
;
5301 * mono_set_break_policy:
5302 * \param policy_callback the new callback function
5304 * Allow embedders to decide whether to actually obey breakpoint instructions
5305 * (both break IL instructions and \c Debugger.Break method calls), for example
5306 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5307 * untrusted or semi-trusted code.
5309 * \p policy_callback will be called every time a break point instruction needs to
5310 * be inserted with the method argument being the method that calls \c Debugger.Break
5311 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5312 * if it wants the breakpoint to not be effective in the given method.
5313 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5316 mono_set_break_policy (MonoBreakPolicyFunc policy_callback
)
5318 if (policy_callback
)
5319 break_policy_func
= policy_callback
;
5321 break_policy_func
= always_insert_breakpoint
;
5325 mini_should_insert_breakpoint (MonoMethod
*method
)
5327 switch (break_policy_func (method
)) {
5328 case MONO_BREAK_POLICY_ALWAYS
:
5330 case MONO_BREAK_POLICY_NEVER
:
5332 case MONO_BREAK_POLICY_ON_DBG
:
5333 g_warning ("mdb no longer supported");
5336 g_warning ("Incorrect value returned from break policy callback");
5341 // Custom handlers currently only implemented by Windows.
5344 mono_runtime_install_custom_handlers (const char *handlers
)
5350 mono_runtime_install_custom_handlers_usage (void)
5353 "Custom Handlers:\n"
5354 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5355 " separated list of available handlers to install.\n"
5357 "No handlers supported on current platform.\n");
5359 #endif /* HOST_WIN32 */
5361 #ifdef ENABLE_METADATA_UPDATE
5363 mini_metadata_update_init (MonoError
*error
)
5365 mini_get_interp_callbacks ()->metadata_update_init (error
);
5369 mini_invalidate_transformed_interp_methods (MonoDomain
*domain
, MonoAssemblyLoadContext
*alc G_GNUC_UNUSED
, uint32_t generation G_GNUC_UNUSED
)
5371 mini_get_interp_callbacks ()->invalidate_transformed (domain
);