3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
28 #include <mono/utils/memcheck.h>
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/assembly-internals.h>
32 #include <mono/metadata/loader.h>
33 #include <mono/metadata/tabledefs.h>
34 #include <mono/metadata/class.h>
35 #include <mono/metadata/object.h>
36 #include <mono/metadata/tokentype.h>
37 #include <mono/metadata/tabledefs.h>
38 #include <mono/metadata/threads.h>
39 #include <mono/metadata/appdomain.h>
40 #include <mono/metadata/debug-helpers.h>
41 #include <mono/metadata/domain-internals.h>
42 #include <mono/metadata/profiler-private.h>
43 #include <mono/metadata/mono-config.h>
44 #include <mono/metadata/environment.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/threads-types.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/runtime.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/metadata/icall-internals.h>
54 #include <mono/metadata/loader-internals.h>
55 #define MONO_MATH_DECLARE_ALL 1
56 #include <mono/utils/mono-math.h>
57 #include <mono/utils/mono-compiler.h>
58 #include <mono/utils/mono-counters.h>
59 #include <mono/utils/mono-error-internals.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-mmap.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-tls.h>
64 #include <mono/utils/mono-hwcap.h>
65 #include <mono/utils/dtrace.h>
66 #include <mono/utils/mono-signal-handler.h>
67 #include <mono/utils/mono-threads.h>
68 #include <mono/utils/mono-threads-coop.h>
69 #include <mono/utils/checked-build.h>
70 #include <mono/utils/mono-compiler.h>
71 #include <mono/utils/mono-proclib.h>
72 #include <mono/utils/mono-state.h>
73 #include <mono/metadata/w32handle.h>
74 #include <mono/metadata/threadpool.h>
77 #include "seq-points.h"
83 #include "aot-compiler.h"
84 #include "aot-runtime.h"
85 #include "llvmonly-runtime.h"
87 #include "jit-icalls.h"
90 #include "mini-llvm.h"
91 #include "debugger-agent.h"
93 #include "mini-runtime.h"
94 #include "interp/interp.h"
96 #ifdef MONO_ARCH_LLVM_SUPPORTED
98 #include "mini-llvm-cpp.h"
102 #include "mono/metadata/icall-signatures.h"
103 #include "mono/utils/mono-tls-inline.h"
105 static guint32 default_opt
= 0;
106 static gboolean default_opt_set
= FALSE
;
108 gboolean mono_compile_aot
= FALSE
;
109 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
110 gboolean mono_aot_only
= FALSE
;
111 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
112 gboolean mono_llvm_only
= FALSE
;
113 /* By default, don't require AOT but attempt to probe */
114 MonoAotMode mono_aot_mode
= MONO_AOT_MODE_NORMAL
;
115 MonoEEFeatures mono_ee_features
;
117 const char *mono_build_date
;
118 gboolean mono_do_signal_chaining
;
119 gboolean mono_do_crash_chaining
;
120 int mini_verbose
= 0;
123 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
124 * it can load AOT code compiled by LLVM.
126 gboolean mono_use_llvm
= FALSE
;
128 gboolean mono_use_fast_math
= FALSE
;
130 // Lists of whitelisted and blacklisted CPU features
131 MonoCPUFeatures mono_cpu_features_enabled
= (MonoCPUFeatures
)0;
132 MonoCPUFeatures mono_cpu_features_disabled
= (MonoCPUFeatures
)0;
134 gboolean mono_use_interpreter
= FALSE
;
135 const char *mono_interp_opts_string
= NULL
;
137 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
138 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
139 static mono_mutex_t jit_mutex
;
141 static MonoCodeManager
*global_codeman
;
143 MonoDebugOptions mini_debug_options
;
146 #ifdef VALGRIND_JIT_REGISTER_MAP
147 int valgrind_register
;
149 GList
* mono_aot_paths
;
151 static GPtrArray
*profile_options
;
153 static GSList
*tramp_infos
;
154 GSList
*mono_interp_only_classes
;
156 static void register_icalls (void);
159 mono_running_on_valgrind (void)
162 if (RUNNING_ON_VALGRIND
){
163 #ifdef VALGRIND_JIT_REGISTER_MAP
164 valgrind_register
= TRUE
;
173 mono_set_use_llvm (mono_bool use_llvm
)
175 mono_use_llvm
= (gboolean
)use_llvm
;
185 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
187 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
190 ud
->method
= (MonoMethod
*)key
;
195 mono_get_method_from_ip (void *ip
)
201 MonoDomain
*domain
= mono_domain_get ();
202 MonoDebugSourceLocation
*location
;
203 FindTrampUserData user_data
;
206 domain
= mono_get_root_domain ();
208 ji
= mono_jit_info_table_find_internal (domain
, ip
, TRUE
, TRUE
);
211 user_data
.method
= NULL
;
212 mono_domain_lock (domain
);
213 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
214 mono_domain_unlock (domain
);
215 if (user_data
.method
) {
216 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
217 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
223 } else if (ji
->is_trampoline
) {
224 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ji
->d
.tramp_info
->name
);
228 method
= jinfo_get_method (ji
);
229 method_name
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_IL
);
230 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
232 char *file_loc
= NULL
;
234 file_loc
= g_strdup_printf ("[%s :: %du]", location
->source_file
, location
->row
);
236 const char *in_interp
= ji
->is_interp
? " interp" : "";
238 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
);
240 mono_debug_free_source_location (location
);
241 g_free (method_name
);
249 * \param ip an instruction pointer address
251 * This method is used from a debugger to get the name of the
252 * method at address \p ip. This routine is typically invoked from
253 * a debugger like this:
255 * (gdb) print mono_pmip ($pc)
257 * \returns the name of the method at address \p ip.
262 return mono_get_method_from_ip (ip
);
266 * mono_print_method_from_ip:
267 * \param ip an instruction pointer address
269 * This method is used from a debugger to get the name of the
270 * method at address \p ip.
272 * This prints the name of the method at address \p ip in the standard
273 * output. Unlike \c mono_pmip which returns a string, this routine
274 * prints the value on the standard output.
277 mono_print_method_from_ip (void *ip
)
281 MonoDebugSourceLocation
*source
;
282 MonoDomain
*domain
= mono_domain_get ();
283 MonoDomain
*target_domain
= mono_domain_get ();
284 FindTrampUserData user_data
;
285 MonoGenericSharingContext
*gsctx
;
286 const char *shared_type
;
289 domain
= mono_get_root_domain ();
290 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
291 if (ji
&& ji
->is_trampoline
) {
292 MonoTrampInfo
*tinfo
= ji
->d
.tramp_info
;
294 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
300 user_data
.method
= NULL
;
301 mono_domain_lock (domain
);
302 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
303 mono_domain_unlock (domain
);
305 if (user_data
.method
) {
306 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
307 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
312 g_print ("No method at %p\n", ip
);
316 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
317 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
319 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
322 if (gsctx
->is_gsharedvt
)
323 shared_type
= "gsharedvt ";
325 shared_type
= "gshared ";
328 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
);
331 g_print ("%s:%d\n", source
->source_file
, source
->row
);
334 mono_debug_free_source_location (source
);
339 * mono_method_same_domain:
341 * Determine whenever two compiled methods are in the same domain, thus
342 * the address of the callee can be embedded in the caller.
344 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
348 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
352 * If the call was made from domain-neutral to domain-specific
353 * code, we can't patch the call site.
355 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
358 cmethod
= jinfo_get_method (caller
);
359 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
360 (strstr (cmethod
->name
, "InvokeInDomain"))) {
361 /* The InvokeInDomain methods change the current appdomain */
369 * mono_global_codeman_reserve:
371 * Allocate code memory from the global code manager.
373 void *(mono_global_codeman_reserve
) (int size
)
378 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
380 if (!global_codeman
) {
381 /* This can happen during startup */
382 global_codeman
= mono_code_manager_new ();
383 return mono_code_manager_reserve (global_codeman
, size
);
387 ptr
= mono_code_manager_reserve (global_codeman
, size
);
393 /* The callback shouldn't take any locks */
395 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
398 mono_code_manager_foreach (global_codeman
, func
, user_data
);
403 * mono_create_unwind_op:
405 * Create an unwind op with the given parameters.
408 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
410 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
421 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
423 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
426 res
->has_context
= context
!= NULL
;
428 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
434 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
436 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
440 * mono_tramp_info_create:
442 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
443 * of JI, and UNWIND_OPS.
446 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
448 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
450 info
->name
= g_strdup (name
);
452 info
->code_size
= code_size
;
454 info
->unwind_ops
= unwind_ops
;
460 mono_tramp_info_free (MonoTrampInfo
*info
)
465 mono_free_unwind_info (info
->unwind_ops
);
466 if (info
->owns_uw_info
)
467 g_free (info
->uw_info
);
472 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
476 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
477 mono_jit_info_init (ji
, NULL
, info
->code
, info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
478 ji
->d
.tramp_info
= info
;
479 ji
->is_trampoline
= TRUE
;
481 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
483 mono_jit_info_table_add (domain
, ji
);
487 * mono_tramp_info_register:
489 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
494 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
502 domain
= mono_get_root_domain ();
505 copy
= mono_domain_alloc0 (domain
, sizeof (MonoTrampInfo
));
507 copy
= g_new0 (MonoTrampInfo
, 1);
509 copy
->code
= info
->code
;
510 copy
->code_size
= info
->code_size
;
511 copy
->name
= g_strdup (info
->name
);
513 if (info
->unwind_ops
) {
514 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
515 copy
->owns_uw_info
= TRUE
;
517 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
518 guint8
*temp
= copy
->uw_info
;
519 copy
->uw_info
= mono_domain_alloc (domain
, copy
->uw_info_len
);
520 memcpy (copy
->uw_info
, temp
, copy
->uw_info_len
);
524 /* Trampolines from aot have the unwind ops already encoded */
525 copy
->uw_info
= info
->uw_info
;
526 copy
->uw_info_len
= info
->uw_info_len
;
529 mono_save_trampoline_xdebug_info (info
);
530 mono_lldb_save_trampoline_info (info
);
532 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
534 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
538 /* If no root domain has been created yet, postpone the registration. */
540 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
542 } else if (copy
->uw_info
) {
543 /* Only register trampolines that have unwind infos */
544 register_trampoline_jit_info (domain
, copy
);
547 if (mono_jit_map_is_enabled ())
548 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
550 mono_tramp_info_free (info
);
554 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
556 mono_tramp_info_register_internal (info
, domain
, FALSE
);
560 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
562 mono_tramp_info_register_internal (info
, domain
, TRUE
);
566 mono_tramp_info_cleanup (void)
570 for (l
= tramp_infos
; l
; l
= l
->next
) {
571 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
573 mono_tramp_info_free (info
);
575 g_slist_free (tramp_infos
);
578 /* Register trampolines created before the root domain was created in the jit info tables */
580 register_trampolines (MonoDomain
*domain
)
584 for (l
= tramp_infos
; l
; l
= l
->next
) {
585 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
587 register_trampoline_jit_info (domain
, info
);
591 G_GNUC_UNUSED
static void
597 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
598 * Set a breakpoint in break_count () to break the last time <x> is done.
600 G_GNUC_UNUSED gboolean
601 mono_debug_count (void)
603 static int count
= 0, int_val
= 0;
604 static gboolean inited
, has_value
= FALSE
;
609 char *value
= g_getenv ("COUNT");
611 int_val
= atoi (value
);
621 if (count
== int_val
)
631 mono_icall_get_wrapper_method (MonoJitICallInfo
* callinfo
)
633 /* This icall is used to check for exceptions, so don't check in the wrapper */
634 gboolean check_exc
= (callinfo
!= &mono_get_jit_icall_info ()->mono_thread_interruption_checkpoint
);
636 return mono_marshal_get_icall_wrapper (callinfo
, check_exc
);
640 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
644 gconstpointer addr
, trampoline
;
645 MonoDomain
*domain
= mono_get_root_domain ();
647 if (callinfo
->wrapper
)
648 return callinfo
->wrapper
;
650 wrapper
= mono_icall_get_wrapper_method (callinfo
);
653 addr
= mono_compile_method_checked (wrapper
, error
);
654 mono_error_assert_ok (error
);
655 mono_memory_barrier ();
656 callinfo
->wrapper
= addr
;
659 if (callinfo
->trampoline
)
660 return callinfo
->trampoline
;
661 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, error
);
662 mono_error_assert_ok (error
);
663 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
666 if (!callinfo
->trampoline
) {
667 callinfo
->trampoline
= trampoline
;
669 mono_loader_unlock ();
671 return callinfo
->trampoline
;
676 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
678 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
681 static MonoJitDynamicMethodInfo
*
682 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
684 MonoJitDynamicMethodInfo
*res
;
686 if (domain_jit_info (domain
)->dynamic_code_hash
)
687 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
694 template <typename T
>
696 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, T func
, const char *symbol
, gboolean no_wrapper
)
699 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, gpointer func
, const char *symbol
, gboolean no_wrapper
)
703 mini_register_opcode_emulation (opcode
, jit_icall_info
, name
, sig
, func
, symbol
, no_wrapper
);
705 // FIXME ifdef in mini_register_opcode_emulation and just call it.
707 g_assert (!sig
->hasthis
);
708 g_assert (sig
->param_count
< 3);
710 mono_register_jit_icall_info (jit_icall_info
, func
, name
, sig
, no_wrapper
, symbol
);
714 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
715 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
718 * For JIT icalls implemented in C.
719 * NAME should be the same as the name of the C function whose address is FUNC.
720 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
721 * can't throw exceptions.
723 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
724 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
726 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
727 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
728 * must be extern "C".
730 #define register_icall(func, sig, avoid_wrapper) \
731 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
733 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
734 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
737 * Register an icall where FUNC is dynamically generated or otherwise not
738 * possible to link to it using NAME during AOT.
740 * func is an expression, such a local variable or a function call to get a function pointer.
741 * name is an identifier
743 * Providing func and name separately is what distinguishes "dyn" from regular.
745 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
747 #define register_dyn_icall(func, name, sig, save) \
748 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
753 MonoJitTlsData
*jit_tls
;
755 if ((jit_tls
= mono_tls_get_jit_tls ()))
758 * We do not assert here because this function can be called from
759 * mini-gc.c on a thread that has not executed any managed code, yet
760 * (the thread object allocation can trigger a collection).
766 mono_set_lmf (MonoLMF
*lmf
)
768 (*mono_get_lmf_addr ()) = lmf
;
772 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
774 MonoThreadInfo
*info
;
776 mono_tls_set_jit_tls (jit_tls
);
778 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
779 info
= mono_thread_info_current ();
781 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
785 mono_set_lmf_addr (MonoLMF
**lmf_addr
)
787 MonoThreadInfo
*info
;
789 mono_tls_set_lmf_addr (lmf_addr
);
791 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
792 info
= mono_thread_info_current ();
794 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
800 * Push an MonoLMFExt frame on the LMF stack.
803 mono_push_lmf (MonoLMFExt
*ext
)
807 lmf_addr
= mono_get_lmf_addr ();
809 ext
->lmf
.previous_lmf
= *lmf_addr
;
810 /* Mark that this is a MonoLMFExt */
811 ext
->lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
->lmf
.previous_lmf
) | 2);
813 mono_set_lmf ((MonoLMF
*)ext
);
819 * Pop the last frame from the LMF stack.
822 mono_pop_lmf (MonoLMF
*lmf
)
824 mono_set_lmf ((MonoLMF
*)(((gssize
)lmf
->previous_lmf
) & ~3));
828 * mono_jit_thread_attach:
830 * Called by Xamarin.Mac and other products. Attach thread to runtime if
831 * needed and switch to @domain.
833 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
835 * If the thread is newly-attached, put into GC Safe mode.
837 * @return the original domain which needs to be restored, or NULL.
840 mono_jit_thread_attach (MonoDomain
*domain
)
846 /* Happens when called from AOTed code which is only used in the root domain. */
847 domain
= mono_get_root_domain ();
852 attached
= mono_tls_get_jit_tls () != NULL
;
855 mono_thread_attach (domain
);
858 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
860 /* mono_jit_thread_attach is external-only and not called by
861 * the runtime on any of our own threads. So if we get here,
862 * the thread is running native code - leave it in GC Safe mode
863 * and leave it to the n2m invoke wrappers or MONO_API entry
864 * points to switch to GC Unsafe.
866 MONO_STACKDATA (stackdata
);
867 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata
);
870 orig
= mono_domain_get ();
872 mono_domain_set_fast (domain
, TRUE
);
874 return orig
!= domain
? orig
: NULL
;
878 * mono_jit_set_domain:
880 * Set domain to @domain if @domain is not null
883 mono_jit_set_domain (MonoDomain
*domain
)
885 g_assert (!mono_threads_is_blocking_transition_enabled ());
888 mono_domain_set_fast (domain
, TRUE
);
893 * \param obj exception object
894 * Abort the thread, print exception information and stack trace
897 mono_thread_abort (MonoObject
*obj
)
899 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
901 /* handle_remove should be eventually called for this thread, too
904 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
905 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
) ||
906 ((obj
->vtable
->klass
) == mono_class_try_get_appdomain_unloaded_exception_class () &&
907 mono_thread_info_current ()->runtime_thread
)) {
910 mono_invoke_unhandled_exception_hook (obj
);
914 static MonoJitTlsData
*
915 setup_jit_tls_data (gpointer stack_start
, MonoAbortFunction abort_func
)
917 MonoJitTlsData
*jit_tls
;
920 jit_tls
= mono_tls_get_jit_tls ();
924 jit_tls
= g_new0 (MonoJitTlsData
, 1);
926 jit_tls
->abort_func
= abort_func
;
927 jit_tls
->end_of_stack
= stack_start
;
929 mono_set_jit_tls (jit_tls
);
931 lmf
= g_new0 (MonoLMF
, 1);
932 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
934 jit_tls
->first_lmf
= lmf
;
936 mono_set_lmf_addr (&jit_tls
->lmf
);
940 #ifdef MONO_ARCH_HAVE_TLS_INIT
941 mono_arch_tls_init ();
944 mono_setup_altstack (jit_tls
);
950 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
952 //This happens during AOT cuz the thread is never attached
955 mono_free_altstack (jit_tls
);
957 if (jit_tls
->interp_context
)
958 mini_get_interp_callbacks ()->free_context (jit_tls
->interp_context
);
960 g_free (jit_tls
->first_lmf
);
965 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
967 MonoThreadInfo
*thread
;
968 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
969 thread
= mono_thread_info_current_unchecked ();
971 thread
->jit_data
= jit_tls
;
973 mono_arch_cpu_init ();
976 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
979 mono_thread_abort_dummy (MonoObject
*obj
)
981 if (mono_thread_attach_aborted_cb
)
982 mono_thread_attach_aborted_cb (obj
);
984 mono_thread_abort (obj
);
988 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
990 MonoThreadInfo
*thread
;
991 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
992 thread
= mono_thread_info_current_unchecked ();
994 thread
->jit_data
= jit_tls
;
996 mono_arch_cpu_init ();
1000 mini_thread_cleanup (MonoNativeThreadId tid
)
1002 MonoJitTlsData
*jit_tls
= NULL
;
1003 MonoThreadInfo
*info
;
1005 info
= mono_thread_info_current_unchecked ();
1007 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1008 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1009 * not a trivial thing.
1011 * The current offender is mono_thread_manage which cleanup threads from the outside.
1013 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
1014 jit_tls
= info
->jit_data
;
1015 info
->jit_data
= NULL
;
1017 mono_set_jit_tls (NULL
);
1019 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1020 if (mono_get_lmf ()) {
1021 mono_set_lmf (NULL
);
1022 mono_set_lmf_addr (NULL
);
1025 info
= mono_thread_info_lookup (tid
);
1027 jit_tls
= info
->jit_data
;
1028 info
->jit_data
= NULL
;
1030 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1034 free_jit_tls_data (jit_tls
);
1038 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
1040 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
1044 ji
->data
.target
= target
;
1050 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1052 static const char* const patch_info_str
[] = {
1053 #define PATCH_INFO(a,b) "" #a,
1054 #include "patch-info.h"
1059 mono_ji_type_to_string (MonoJumpInfoType type
)
1061 return patch_info_str
[type
];
1065 mono_print_ji (const MonoJumpInfo
*ji
)
1067 const char *type
= patch_info_str
[ji
->type
];
1069 case MONO_PATCH_INFO_RGCTX_FETCH
:
1070 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1071 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1073 printf ("[%s ", type
);
1074 mono_print_ji (entry
->data
);
1075 printf (" -> %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1078 case MONO_PATCH_INFO_METHOD
:
1079 case MONO_PATCH_INFO_METHODCONST
:
1080 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1081 char *s
= mono_method_get_full_name (ji
->data
.method
);
1082 printf ("[%s %s]", type
, s
);
1086 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1087 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji
->data
.jit_icall_id
)->name
);
1089 case MONO_PATCH_INFO_CLASS
:
1090 case MONO_PATCH_INFO_VTABLE
: {
1091 char *name
= mono_class_full_name (ji
->data
.klass
);
1092 printf ("[%s %s]", type
, name
);
1097 printf ("[%s]", type
);
1105 mono_ji_type_to_string (MonoJumpInfoType type
)
1111 mono_print_ji (const MonoJumpInfo
*ji
)
1118 * mono_patch_info_dup_mp:
1120 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1123 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1125 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1126 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1128 switch (patch_info
->type
) {
1129 case MONO_PATCH_INFO_RVA
:
1130 case MONO_PATCH_INFO_LDSTR
:
1131 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1132 case MONO_PATCH_INFO_LDTOKEN
:
1133 case MONO_PATCH_INFO_DECLSEC
:
1134 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1135 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1137 case MONO_PATCH_INFO_SWITCH
:
1138 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1139 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1140 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1141 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1143 case MONO_PATCH_INFO_RGCTX_FETCH
:
1144 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1145 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1146 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1147 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1149 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1150 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1151 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1153 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1154 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1155 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1157 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1158 MonoGSharedVtMethodInfo
*info
;
1159 MonoGSharedVtMethodInfo
*oinfo
;
1162 oinfo
= patch_info
->data
.gsharedvt_method
;
1163 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1164 res
->data
.gsharedvt_method
= info
;
1165 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1166 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1167 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1168 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1169 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1171 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1173 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1174 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1177 case MONO_PATCH_INFO_VIRT_METHOD
: {
1178 MonoJumpInfoVirtMethod
*info
;
1179 MonoJumpInfoVirtMethod
*oinfo
;
1181 oinfo
= patch_info
->data
.virt_method
;
1182 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1183 res
->data
.virt_method
= info
;
1184 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1195 mono_patch_info_hash (gconstpointer data
)
1197 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1198 const MonoJumpInfoType type
= ji
->type
;
1199 guint hash
= type
<< 8;
1202 case MONO_PATCH_INFO_RVA
:
1203 case MONO_PATCH_INFO_LDSTR
:
1204 case MONO_PATCH_INFO_LDTOKEN
:
1205 case MONO_PATCH_INFO_DECLSEC
:
1206 return hash
| ji
->data
.token
->token
;
1207 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1208 return hash
| ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1209 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: // Hash on the selector name
1210 case MONO_PATCH_INFO_LDSTR_LIT
:
1211 return g_str_hash (ji
->data
.name
);
1212 case MONO_PATCH_INFO_VTABLE
:
1213 case MONO_PATCH_INFO_CLASS
:
1214 case MONO_PATCH_INFO_IID
:
1215 case MONO_PATCH_INFO_ADJUSTED_IID
:
1216 case MONO_PATCH_INFO_METHODCONST
:
1217 case MONO_PATCH_INFO_METHOD
:
1218 case MONO_PATCH_INFO_METHOD_JUMP
:
1219 case MONO_PATCH_INFO_METHOD_FTNDESC
:
1220 case MONO_PATCH_INFO_IMAGE
:
1221 case MONO_PATCH_INFO_ICALL_ADDR
:
1222 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1223 case MONO_PATCH_INFO_FIELD
:
1224 case MONO_PATCH_INFO_SFLDA
:
1225 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1226 case MONO_PATCH_INFO_METHOD_RGCTX
:
1227 case MONO_PATCH_INFO_SIGNATURE
:
1228 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1229 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1230 return hash
| (gssize
)ji
->data
.target
;
1231 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1232 return hash
| (gssize
)ji
->data
.gsharedvt
->method
;
1233 case MONO_PATCH_INFO_RGCTX_FETCH
:
1234 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1235 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1236 hash
|= e
->in_mrgctx
| e
->info_type
| mono_patch_info_hash (e
->data
);
1238 return hash
| (gssize
)e
->d
.method
;
1240 return hash
| (gssize
)e
->d
.klass
;
1242 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1243 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1244 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1245 case MONO_PATCH_INFO_GC_NURSERY_START
:
1246 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1247 case MONO_PATCH_INFO_GOT_OFFSET
:
1248 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1249 case MONO_PATCH_INFO_AOT_MODULE
:
1250 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
:
1251 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
:
1253 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1254 return hash
| ji
->data
.uindex
;
1255 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1256 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1257 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1258 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1259 return hash
| ji
->data
.index
;
1260 case MONO_PATCH_INFO_SWITCH
:
1261 return hash
| ji
->data
.table
->table_size
;
1262 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1263 return hash
| (gssize
)ji
->data
.gsharedvt_method
->method
;
1264 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1265 return hash
| (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1266 case MONO_PATCH_INFO_VIRT_METHOD
: {
1267 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1269 return hash
| (gssize
)info
->klass
| (gssize
)info
->method
;
1271 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1272 return hash
| mono_signature_hash (ji
->data
.sig
);
1274 printf ("info type: %d\n", ji
->type
);
1275 mono_print_ji (ji
); printf ("\n");
1276 g_assert_not_reached ();
1277 case MONO_PATCH_INFO_NONE
:
1283 * mono_patch_info_equal:
1285 * This might fail to recognize equivalent patches, i.e. floats, so its only
1286 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1290 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1292 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1293 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1295 MonoJumpInfoType
const ji1_type
= ji1
->type
;
1296 MonoJumpInfoType
const ji2_type
= ji2
->type
;
1298 if (ji1_type
!= ji2_type
)
1302 case MONO_PATCH_INFO_RVA
:
1303 case MONO_PATCH_INFO_LDSTR
:
1304 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1305 case MONO_PATCH_INFO_LDTOKEN
:
1306 case MONO_PATCH_INFO_DECLSEC
:
1307 return ji1
->data
.token
->image
== ji2
->data
.token
->image
&&
1308 ji1
->data
.token
->token
== ji2
->data
.token
->token
&&
1309 ji1
->data
.token
->has_context
== ji2
->data
.token
->has_context
&&
1310 ji1
->data
.token
->context
.class_inst
== ji2
->data
.token
->context
.class_inst
&&
1311 ji1
->data
.token
->context
.method_inst
== ji2
->data
.token
->context
.method_inst
;
1312 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1313 case MONO_PATCH_INFO_LDSTR_LIT
:
1314 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1315 case MONO_PATCH_INFO_RGCTX_FETCH
:
1316 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1317 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1318 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1320 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
);
1322 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1323 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1324 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1326 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1328 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1329 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1330 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1331 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
;
1332 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1333 return ji1
->data
.uindex
== ji2
->data
.uindex
;
1334 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1335 return ji1
->data
.index
== ji2
->data
.index
;
1336 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1337 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1338 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1339 return ji1
->data
.jit_icall_id
== ji2
->data
.jit_icall_id
;
1340 case MONO_PATCH_INFO_VIRT_METHOD
:
1341 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1342 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1343 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
);
1344 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1345 case MONO_PATCH_INFO_NONE
:
1351 return ji1
->data
.target
== ji2
->data
.target
;
1355 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1357 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1358 gconstpointer target
= NULL
;
1362 switch (patch_info
->type
) {
1363 case MONO_PATCH_INFO_BB
:
1365 * FIXME: This could be hit for methods without a prolog. Should use -1
1366 * but too much code depends on a 0 initial value.
1368 //g_assert (patch_info->data.bb->native_offset);
1369 target
= patch_info
->data
.bb
->native_offset
+ code
;
1371 case MONO_PATCH_INFO_ABS
:
1372 target
= patch_info
->data
.target
;
1374 case MONO_PATCH_INFO_LABEL
:
1375 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1377 case MONO_PATCH_INFO_IP
:
1380 case MONO_PATCH_INFO_JIT_ICALL_ID
: {
1381 MonoJitICallInfo
* const mi
= mono_find_jit_icall_info (patch_info
->data
.jit_icall_id
);
1382 target
= mono_icall_get_wrapper (mi
);
1385 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1386 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
: {
1387 MonoJitICallInfo
* const mi
= mono_find_jit_icall_info (patch_info
->data
.jit_icall_id
);
1391 case MONO_PATCH_INFO_METHOD_JUMP
:
1392 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1396 case MONO_PATCH_INFO_METHOD
:
1397 if (patch_info
->data
.method
== method
) {
1400 /* get the trampoline to the method from the domain */
1401 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1406 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1408 * Return an ftndesc for either AOTed code, or for an interp entry.
1410 target
= mini_llvmonly_load_method_ftndesc (patch_info
->data
.method
, FALSE
, FALSE
, error
);
1411 return_val_if_nok (error
, NULL
);
1414 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1417 mono_domain_lock (domain
);
1418 if (!domain_jit_info (domain
)->method_code_hash
)
1419 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1420 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1422 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1423 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1425 mono_domain_unlock (domain
);
1429 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1430 target
= (gpointer
)&mono_polling_required
;
1432 case MONO_PATCH_INFO_SWITCH
: {
1433 gpointer
*jump_table
;
1435 if (method
&& method
->dynamic
) {
1436 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1438 if (mono_aot_only
) {
1439 jump_table
= (void **)mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1441 jump_table
= (void **)mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1445 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1446 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1449 target
= jump_table
;
1452 case MONO_PATCH_INFO_METHODCONST
:
1453 case MONO_PATCH_INFO_CLASS
:
1454 case MONO_PATCH_INFO_IMAGE
:
1455 case MONO_PATCH_INFO_FIELD
:
1456 case MONO_PATCH_INFO_SIGNATURE
:
1457 case MONO_PATCH_INFO_AOT_MODULE
:
1458 target
= patch_info
->data
.target
;
1460 case MONO_PATCH_INFO_IID
:
1461 mono_class_init_internal (patch_info
->data
.klass
);
1462 target
= GUINT_TO_POINTER (m_class_get_interface_id (patch_info
->data
.klass
));
1464 case MONO_PATCH_INFO_ADJUSTED_IID
:
1465 mono_class_init_internal (patch_info
->data
.klass
);
1466 target
= GUINT_TO_POINTER ((guint32
)(-((m_class_get_interface_id (patch_info
->data
.klass
) + 1) * TARGET_SIZEOF_VOID_P
)));
1468 case MONO_PATCH_INFO_VTABLE
:
1469 target
= mono_class_vtable_checked (domain
, patch_info
->data
.klass
, error
);
1470 mono_error_assert_ok (error
);
1472 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1473 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1475 if (del_tramp
->is_virtual
)
1476 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1478 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1481 case MONO_PATCH_INFO_SFLDA
: {
1482 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, patch_info
->data
.field
->parent
, error
);
1483 mono_error_assert_ok (error
);
1485 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1486 gpointer addr
= NULL
;
1488 mono_domain_lock (domain
);
1489 if (domain
->special_static_fields
)
1490 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1491 mono_domain_unlock (domain
);
1496 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (!method
|| mono_class_needs_cctor_run (vtable
->klass
, method
)))
1497 /* Done by the generated code */
1501 if (!mono_runtime_class_init_full (vtable
, error
)) {
1506 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1509 case MONO_PATCH_INFO_RVA
: {
1510 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1513 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1514 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1517 case MONO_PATCH_INFO_R4
:
1518 case MONO_PATCH_INFO_R8
:
1519 target
= patch_info
->data
.target
;
1521 case MONO_PATCH_INFO_EXC_NAME
:
1522 target
= patch_info
->data
.name
;
1524 case MONO_PATCH_INFO_LDSTR
:
1526 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1527 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1529 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1531 MonoClass
*handle_class
;
1533 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1534 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1537 mono_class_init_internal (handle_class
);
1538 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType
*)handle
));
1540 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1545 case MONO_PATCH_INFO_LDTOKEN
: {
1547 MonoClass
*handle_class
;
1549 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1550 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1551 mono_error_assert_msg_ok (error
, "Could not patch ldtoken");
1552 mono_class_init_internal (handle_class
);
1557 case MONO_PATCH_INFO_DECLSEC
:
1558 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1560 case MONO_PATCH_INFO_ICALL_ADDR
:
1561 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1562 /* run_cctors == 0 -> AOT */
1563 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1565 target
= mono_lookup_pinvoke_call_internal (patch_info
->data
.method
, error
);
1569 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
));
1575 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1577 if (mono_is_missing_icall_addr (target
) && run_cctors
)
1578 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1581 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1582 target
= &mono_thread_interruption_request_flag
;
1584 case MONO_PATCH_INFO_METHOD_RGCTX
:
1585 target
= mini_method_get_rgctx (patch_info
->data
.method
);
1587 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1588 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1590 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1593 case MONO_PATCH_INFO_BB_OVF
:
1594 case MONO_PATCH_INFO_EXC_OVF
:
1595 case MONO_PATCH_INFO_GOT_OFFSET
:
1596 case MONO_PATCH_INFO_NONE
:
1598 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1599 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1601 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1604 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1605 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1607 /* AOT, not needed */
1610 target
= mono_arch_get_seq_point_info (domain
, code
);
1613 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1614 int card_table_shift_bits
;
1615 gpointer card_table_mask
;
1617 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1620 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1624 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1627 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1631 mono_gc_get_nursery (&shift_bits
, &size
);
1633 target
= (gpointer
)(gssize
)shift_bits
;
1636 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1637 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1640 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1644 case MONO_PATCH_INFO_LDSTR_LIT
: {
1648 len
= strlen ((const char *)patch_info
->data
.target
);
1649 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1650 memcpy (s
, patch_info
->data
.target
, len
);
1655 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1656 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1658 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
: {
1659 target
= (gpointer
) &mono_profiler_state
.gc_allocation_count
;
1662 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
: {
1663 target
= (gpointer
) &mono_profiler_state
.exception_clause_count
;
1667 g_assert_not_reached ();
1670 return (gpointer
)target
;
1674 * mini_register_jump_site:
1676 * Register IP as a jump/tailcall site which calls METHOD.
1677 * This is needed because common_call_trampoline () cannot patch
1678 * the call site because the caller ip is not available for jumps.
1681 mini_register_jump_site (MonoDomain
*domain
, MonoMethod
*method
, gpointer ip
)
1683 MonoJumpList
*jlist
;
1685 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1686 method
= shared_method
? shared_method
: method
;
1688 mono_domain_lock (domain
);
1689 jlist
= (MonoJumpList
*)g_hash_table_lookup (domain_jit_info (domain
)->jump_target_hash
, method
);
1691 jlist
= (MonoJumpList
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpList
));
1692 g_hash_table_insert (domain_jit_info (domain
)->jump_target_hash
, method
, jlist
);
1694 jlist
->list
= g_slist_prepend (jlist
->list
, ip
);
1695 mono_domain_unlock (domain
);
1699 * mini_patch_jump_sites:
1701 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1704 mini_patch_jump_sites (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1706 GHashTable
*hash
= domain_jit_info (domain
)->jump_target_hash
;
1711 MonoJumpInfo patch_info
;
1712 MonoJumpList
*jlist
;
1715 /* The caller/callee might use different instantiations */
1716 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1717 method
= shared_method
? shared_method
: method
;
1719 mono_domain_lock (domain
);
1720 jlist
= (MonoJumpList
*)g_hash_table_lookup (hash
, method
);
1722 g_hash_table_remove (hash
, method
);
1723 mono_domain_unlock (domain
);
1725 patch_info
.next
= NULL
;
1726 patch_info
.ip
.i
= 0;
1727 patch_info
.type
= MONO_PATCH_INFO_METHOD_JUMP
;
1728 patch_info
.data
.method
= method
;
1730 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1731 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
)
1732 mono_arch_patch_code_new (NULL
, domain
, (guint8
*)tmp
->data
, &patch_info
, addr
);
1734 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1735 // for gshared methods
1736 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
1738 mono_arch_patch_code (NULL
, NULL
, domain
, tmp
->data
, &patch_info
, TRUE
, error
);
1739 mono_error_assert_ok (error
);
1746 * mini_patch_llvm_jit_callees:
1748 * Patch function address slots used by llvm JITed code.
1751 mini_patch_llvm_jit_callees (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1753 if (!domain_jit_info (domain
)->llvm_jit_callees
)
1755 GSList
*callees
= (GSList
*)g_hash_table_lookup (domain_jit_info (domain
)->llvm_jit_callees
, method
);
1758 for (l
= callees
; l
; l
= l
->next
) {
1759 gpointer
*slot
= (gpointer
*)l
->data
;
1766 mini_init_gsctx (MonoDomain
*domain
, MonoMemPool
*mp
, MonoGenericContext
*context
, MonoGenericSharingContext
*gsctx
)
1768 MonoGenericInst
*inst
;
1771 memset (gsctx
, 0, sizeof (MonoGenericSharingContext
));
1773 if (context
&& context
->class_inst
) {
1774 inst
= context
->class_inst
;
1775 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1776 MonoType
*type
= inst
->type_argv
[i
];
1778 if (mini_is_gsharedvt_gparam (type
))
1779 gsctx
->is_gsharedvt
= TRUE
;
1782 if (context
&& context
->method_inst
) {
1783 inst
= context
->method_inst
;
1785 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1786 MonoType
*type
= inst
->type_argv
[i
];
1788 if (mini_is_gsharedvt_gparam (type
))
1789 gsctx
->is_gsharedvt
= TRUE
;
1795 * LOCKING: Acquires the jit code hash lock.
1798 mini_lookup_method (MonoDomain
*domain
, MonoMethod
*method
, MonoMethod
*shared
)
1801 static gboolean inited
= FALSE
;
1802 static int lookups
= 0;
1803 static int failed_lookups
= 0;
1805 mono_domain_jit_code_hash_lock (domain
);
1806 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
1807 if (!ji
&& shared
) {
1808 /* Try generic sharing */
1809 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, shared
);
1810 if (ji
&& !ji
->has_generic_jit_info
)
1813 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &lookups
);
1814 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &failed_lookups
);
1822 mono_domain_jit_code_hash_unlock (domain
);
1828 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
1834 ji
= mini_lookup_method (domain
, method
, NULL
);
1837 if (!mono_method_is_generic_sharable (method
, FALSE
))
1839 shared
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
1840 mono_error_assert_ok (error
);
1841 ji
= mini_lookup_method (domain
, method
, shared
);
1848 mini_get_class (MonoMethod
*method
, guint32 token
, MonoGenericContext
*context
)
1853 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1854 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
1856 klass
= mono_class_inflate_generic_class_checked (klass
, context
, error
);
1857 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1860 klass
= mono_class_get_and_inflate_typespec_checked (m_class_get_image (method
->klass
), token
, context
, error
);
1861 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1864 mono_class_init_internal (klass
);
1869 static FILE* perf_map_file
;
1872 mono_enable_jit_map (void)
1874 if (!perf_map_file
) {
1876 g_snprintf (name
, sizeof (name
), "/tmp/perf-%d.map", getpid ());
1878 perf_map_file
= fopen (name
, "w");
1883 mono_emit_jit_tramp (void *start
, int size
, const char *desc
)
1886 fprintf (perf_map_file
, "%llx %x %s\n", (long long unsigned int)(gsize
)start
, size
, desc
);
1890 mono_emit_jit_map (MonoJitInfo
*jinfo
)
1892 if (perf_map_file
) {
1893 char *name
= mono_method_full_name (jinfo_get_method (jinfo
), TRUE
);
1894 mono_emit_jit_tramp (jinfo
->code_start
, jinfo
->code_size
, name
);
1900 mono_jit_map_is_enabled (void)
1902 return perf_map_file
!= NULL
;
1908 no_gsharedvt_in_wrapper (void)
1910 g_assert_not_reached ();
1916 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.
1917 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1918 Dependency management in this case is too complex to justify implementing it.
1920 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1923 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1924 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1925 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1926 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1931 int compilation_count
; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1932 int ref_count
; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1933 int threads_waiting
; /* Number of threads waiting on this job */
1934 gboolean has_cond
; /* True if @cond was initialized */
1935 gboolean done
; /* True if the method finished JIT'ing */
1936 MonoCoopCond cond
; /* Cond sleeping threads wait one */
1937 } JitCompilationEntry
;
1940 GPtrArray
*in_flight_methods
; //JitCompilationEntry*
1942 } JitCompilationData
;
1945 Timeout, in millisecounds, that we wait other threads to finish JITing.
1946 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.
1948 #define MAX_JIT_TIMEOUT_MS 1000
1951 static JitCompilationData compilation_data
;
1952 static int jit_methods_waited
, jit_methods_multiple
, jit_methods_overload
, jit_spurious_wakeups_or_timeouts
;
1955 mini_jit_init_job_control (void)
1957 mono_coop_mutex_init (&compilation_data
.lock
);
1958 compilation_data
.in_flight_methods
= g_ptr_array_new ();
1962 lock_compilation_data (void)
1964 mono_coop_mutex_lock (&compilation_data
.lock
);
1968 unlock_compilation_data (void)
1970 mono_coop_mutex_unlock (&compilation_data
.lock
);
1973 static JitCompilationEntry
*
1974 find_method (MonoMethod
*method
, MonoDomain
*domain
)
1977 for (i
= 0; i
< compilation_data
.in_flight_methods
->len
; ++i
){
1978 JitCompilationEntry
*e
= (JitCompilationEntry
*)compilation_data
.in_flight_methods
->pdata
[i
];
1979 if (e
->method
== method
&& e
->domain
== domain
)
1987 add_current_thread (MonoJitTlsData
*jit_tls
)
1989 ++jit_tls
->active_jit_methods
;
1993 unref_jit_entry (JitCompilationEntry
*entry
)
1996 if (entry
->ref_count
)
1998 if (entry
->has_cond
)
1999 mono_coop_cond_destroy (&entry
->cond
);
2004 * Returns true if this method waited successfully for another thread to JIT it
2007 wait_or_register_method_to_compile (MonoMethod
*method
, MonoDomain
*domain
)
2009 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2010 JitCompilationEntry
*entry
;
2012 static gboolean inited
;
2014 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_waited
);
2015 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_multiple
);
2016 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_overload
);
2017 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_spurious_wakeups_or_timeouts
);
2021 lock_compilation_data ();
2023 if (!(entry
= find_method (method
, domain
))) {
2024 entry
= g_new0 (JitCompilationEntry
, 1);
2025 entry
->method
= method
;
2026 entry
->domain
= domain
;
2027 entry
->compilation_count
= entry
->ref_count
= 1;
2028 g_ptr_array_add (compilation_data
.in_flight_methods
, entry
);
2029 g_assert (find_method (method
, domain
) == entry
);
2030 add_current_thread (jit_tls
);
2032 unlock_compilation_data ();
2034 } else if (jit_tls
->active_jit_methods
> 0 || mono_threads_is_current_thread_in_protected_block ()) {
2035 //We can't suspend the current thread if it's already JITing a method.
2036 //Dependency management is too compilated and we want to get rid of this anyways.
2038 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2039 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2041 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2042 ++entry
->compilation_count
;
2043 ++jit_methods_multiple
;
2044 ++jit_tls
->active_jit_methods
;
2046 unlock_compilation_data ();
2049 ++jit_methods_waited
;
2052 if (!entry
->has_cond
) {
2053 mono_coop_cond_init (&entry
->cond
);
2054 entry
->has_cond
= TRUE
;
2058 ++entry
->threads_waiting
;
2060 g_assert (entry
->has_cond
);
2061 mono_coop_cond_timedwait (&entry
->cond
, &compilation_data
.lock
, MAX_JIT_TIMEOUT_MS
);
2062 --entry
->threads_waiting
;
2065 unref_jit_entry (entry
);
2066 unlock_compilation_data ();
2069 //We hit the timeout or a spurious wakeup, fallback to JITing
2070 g_assert (entry
->ref_count
> 1);
2071 unref_jit_entry (entry
);
2072 ++jit_spurious_wakeups_or_timeouts
;
2074 ++entry
->compilation_count
;
2075 ++jit_methods_multiple
;
2076 ++jit_tls
->active_jit_methods
;
2078 unlock_compilation_data ();
2086 unregister_method_for_compile (MonoMethod
*method
, MonoDomain
*target_domain
)
2088 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2090 lock_compilation_data ();
2092 g_assert (jit_tls
->active_jit_methods
> 0);
2093 --jit_tls
->active_jit_methods
;
2095 JitCompilationEntry
*entry
= find_method (method
, target_domain
);
2096 g_assert (entry
); // It would be weird to fail
2099 if (entry
->threads_waiting
) {
2100 g_assert (entry
->has_cond
);
2101 mono_coop_cond_broadcast (&entry
->cond
);
2104 if (--entry
->compilation_count
== 0) {
2105 g_ptr_array_remove (compilation_data
.in_flight_methods
, entry
);
2106 unref_jit_entry (entry
);
2109 unlock_compilation_data ();
2113 create_jit_info_for_trampoline (MonoMethod
*wrapper
, MonoTrampInfo
*info
)
2115 MonoDomain
*domain
= mono_get_root_domain ();
2120 if (info
->uw_info
) {
2121 uw_info
= info
->uw_info
;
2122 info_len
= info
->uw_info_len
;
2124 uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, &info_len
);
2127 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
);
2128 jinfo
->d
.method
= wrapper
;
2129 jinfo
->code_start
= info
->code
;
2130 jinfo
->code_size
= info
->code_size
;
2131 jinfo
->unwind_info
= mono_cache_unwind_info (uw_info
, info_len
);
2140 compile_special (MonoMethod
*method
, MonoDomain
*target_domain
, MonoError
*error
)
2145 if (mono_llvm_only
) {
2146 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2147 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2149 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
) {
2151 * These wrappers are only created for signatures which are in the program, but
2152 * sometimes we load methods too eagerly and have to create them even if they
2153 * will never be called.
2155 return (gpointer
)no_gsharedvt_in_wrapper
;
2160 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
2161 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
2162 MonoMethodPInvoke
* piinfo
= (MonoMethodPInvoke
*) method
;
2164 if (!piinfo
->addr
) {
2165 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
2166 piinfo
->addr
= mono_lookup_internal_call (method
);
2167 else if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
2169 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
);
2171 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
);
2174 ERROR_DECL (ignored_error
);
2175 mono_lookup_pinvoke_call_internal (method
, ignored_error
);
2176 mono_error_cleanup (ignored_error
);
2180 MonoMethod
*nm
= mono_marshal_get_native_wrapper (method
, TRUE
, mono_aot_only
);
2181 gpointer compiled_method
= mono_jit_compile_method_jit_only (nm
, error
);
2182 return_val_if_nok (error
, NULL
);
2184 code
= mono_get_addr_from_ftnptr (compiled_method
);
2185 jinfo
= mono_jit_info_table_find (target_domain
, code
);
2187 jinfo
= mono_jit_info_table_find (mono_domain_get (), code
);
2189 MONO_PROFILER_RAISE (jit_done
, (method
, jinfo
));
2191 } else if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
2192 const char *name
= method
->name
;
2196 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2197 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
2198 MonoJitICallInfo
*mi
= &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor
;
2200 * We need to make sure this wrapper
2201 * is compiled because it might end up
2202 * in an (M)RGCTX if generic sharing
2203 * is enabled, and would be called
2204 * indirectly. If it were a
2205 * trampoline we'd try to patch that
2206 * indirect call, which is not
2209 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper_full (mi
, TRUE
));
2210 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2211 if (mono_llvm_only
) {
2212 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
2213 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2214 return_val_if_nok (error
, NULL
);
2215 return mono_get_addr_from_ftnptr (compiled_ptr
);
2218 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2219 if (mono_use_interpreter
)
2222 return mono_create_delegate_trampoline (target_domain
, method
->klass
);
2223 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
2224 nm
= mono_marshal_get_delegate_begin_invoke (method
);
2225 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2226 return_val_if_nok (error
, NULL
);
2227 return mono_get_addr_from_ftnptr (compiled_ptr
);
2228 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
2229 nm
= mono_marshal_get_delegate_end_invoke (method
);
2230 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2231 return_val_if_nok (error
, NULL
);
2232 return mono_get_addr_from_ftnptr (compiled_ptr
);
2236 full_name
= mono_method_full_name (method
, TRUE
);
2237 mono_error_set_invalid_program (error
, "Unrecognizable runtime implemented method '%s'", full_name
);
2242 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2243 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2245 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
|| info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_OUT
) {
2246 static MonoTrampInfo
*in_tinfo
, *out_tinfo
;
2247 MonoTrampInfo
*tinfo
;
2249 gboolean is_in
= info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
;
2251 if (is_in
&& in_tinfo
)
2252 return in_tinfo
->code
;
2253 else if (!is_in
&& out_tinfo
)
2254 return out_tinfo
->code
;
2257 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2259 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2261 if (mono_ee_features
.use_aot_trampolines
)
2262 mono_aot_get_trampoline_full (is_in
? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo
);
2264 mono_arch_get_gsharedvt_trampoline (&tinfo
, FALSE
);
2265 jinfo
= create_jit_info_for_trampoline (method
, tinfo
);
2266 mono_jit_info_table_add (mono_get_root_domain (), jinfo
);
2279 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
2281 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
2283 gpointer code
= NULL
, p
;
2285 MonoJitICallInfo
*callinfo
= NULL
;
2286 WrapperInfo
*winfo
= NULL
;
2287 gboolean use_interp
= FALSE
;
2291 if (mono_ee_features
.force_use_interpreter
&& !jit_only
)
2293 if (!use_interp
&& mono_interp_only_classes
) {
2294 for (GSList
*l
= mono_interp_only_classes
; l
; l
= l
->next
) {
2295 if (!strcmp (m_class_get_name (method
->klass
), (char*)l
->data
))
2300 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2306 /* Should be handled by the caller */
2307 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
2310 * ICALL wrappers are handled specially, since there is only one copy of them
2311 * shared by all appdomains.
2313 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2314 winfo
= mono_marshal_get_wrapper_info (method
);
2315 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
2316 callinfo
= mono_find_jit_icall_info (winfo
->d
.icall
.jit_icall_id
);
2318 /* Must be domain neutral since there is only one copy */
2319 opt
|= MONO_OPT_SHARED
;
2321 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2322 opt
&= ~MONO_OPT_SHARED
;
2325 if (opt
& MONO_OPT_SHARED
)
2326 target_domain
= mono_get_root_domain ();
2328 target_domain
= domain
;
2330 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2331 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2334 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
2335 MonoGenericContext
*ctx
= NULL
;
2336 if (method
->is_inflated
)
2337 ctx
= mono_method_get_context (method
);
2338 method
= info
->d
.synchronized_inner
.method
;
2340 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2341 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
2347 info
= lookup_method (target_domain
, method
);
2349 /* We can't use a domain specific method in another domain */
2350 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2353 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2354 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2358 if (!mono_runtime_class_init_full (vtable
, error
))
2360 return mono_create_ftnptr (target_domain
, info
->code_start
);
2364 #ifdef MONO_USE_AOT_COMPILER
2365 if (opt
& MONO_OPT_AOT
) {
2366 MonoDomain
*domain
= NULL
;
2368 if (mono_aot_mode
== MONO_AOT_MODE_INTERP
&& method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2369 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2371 if (info
->subtype
== WRAPPER_SUBTYPE_INTERP_IN
|| info
->subtype
== WRAPPER_SUBTYPE_INTERP_LMF
)
2372 /* AOT'd wrappers for interp must be owned by root domain */
2373 domain
= mono_get_root_domain ();
2377 domain
= mono_domain_get ();
2379 mono_class_init_internal (method
->klass
);
2381 code
= mono_aot_get_method (domain
, method
, error
);
2385 if (mono_gc_is_critical_method (method
)) {
2387 * The suspend code needs to be able to lookup these methods by ip in async context,
2388 * so preload their jit info.
2390 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, code
);
2395 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2396 * This is not a problem, since it will be initialized when the method is first
2397 * called by init_method ().
2399 if (!mono_llvm_only
&& !mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2400 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2401 mono_error_assert_ok (error
);
2402 if (!mono_runtime_class_init_full (vtable
, error
))
2412 code
= compile_special (method
, target_domain
, error
);
2418 if (!jit_only
&& !code
&& mono_aot_only
&& mono_use_interpreter
&& method
->wrapper_type
!= MONO_WRAPPER_OTHER
) {
2419 if (mono_llvm_only
) {
2420 /* Signal to the caller that AOTed code is not found */
2423 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2430 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2431 char *full_name
= mono_type_get_full_name (method
->klass
);
2432 mono_error_set_invalid_operation (error
, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name
);
2437 if (mono_aot_only
) {
2438 char *fullname
= mono_method_get_full_name (method
);
2439 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
);
2445 if (wait_or_register_method_to_compile (method
, target_domain
))
2447 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2448 unregister_method_for_compile (method
, target_domain
);
2453 if (!code
&& mono_llvm_only
) {
2454 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2455 g_assert_not_reached ();
2461 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2463 if ((method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
)) {
2467 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2469 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2474 p
= mono_create_ftnptr (target_domain
, code
);
2477 // FIXME Locking here is somewhat historical due to mono_register_jit_icall_wrapper taking loader lock.
2478 // atomic_compare_exchange should suffice.
2479 mono_loader_lock ();
2481 if (!callinfo
->wrapper
) {
2482 callinfo
->wrapper
= p
;
2485 mono_loader_unlock ();
2488 // FIXME p or callinfo->wrapper or does not matter?
2493 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2497 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2502 * mono_jit_compile_method_jit_only:
2504 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2507 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2511 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2515 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2517 invalidated_delegate_trampoline (char *desc
)
2519 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2520 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2526 * mono_jit_free_method:
2528 * Free all memory allocated by the JIT for METHOD.
2531 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2533 MonoJitDynamicMethodInfo
*ji
;
2534 gboolean destroy
= TRUE
, removed
;
2535 GHashTableIter iter
;
2536 MonoJumpList
*jlist
;
2537 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2539 g_assert (method
->dynamic
);
2541 if (mono_use_interpreter
) {
2542 mini_get_interp_callbacks ()->free_method (domain
, method
);
2545 mono_domain_lock (domain
);
2546 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2547 mono_domain_unlock (domain
);
2552 mono_debug_remove_method (method
, domain
);
2553 mono_lldb_remove_method (domain
, method
, ji
);
2555 mono_domain_lock (domain
);
2556 g_hash_table_remove (info
->dynamic_code_hash
, method
);
2557 mono_domain_jit_code_hash_lock (domain
);
2558 removed
= mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2560 mono_domain_jit_code_hash_unlock (domain
);
2561 g_hash_table_remove (info
->jump_trampoline_hash
, method
);
2562 g_hash_table_remove (info
->seq_points
, method
);
2564 ji
->ji
->seq_points
= NULL
;
2566 /* requires the domain lock - took above */
2567 mono_conc_hashtable_remove (info
->runtime_invoke_hash
, method
);
2569 /* Remove jump targets in this method */
2570 g_hash_table_iter_init (&iter
, info
->jump_target_hash
);
2571 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2572 GSList
*tmp
, *remove
;
2575 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2576 guint8
*ip
= (guint8
*)tmp
->data
;
2578 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2579 remove
= g_slist_prepend (remove
, tmp
);
2581 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2582 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2584 g_slist_free (remove
);
2586 mono_domain_unlock (domain
);
2588 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2589 if (mini_debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2591 * Instead of freeing the code, change it to call an error routine
2592 * so people can fix their code.
2594 char *type
= mono_type_full_name (m_class_get_byval_arg (method
->klass
));
2595 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2598 mono_arch_invalidate_method (ji
->ji
, (gpointer
)invalidated_delegate_trampoline
, (gpointer
)type_and_method
);
2604 * This needs to be done before freeing code_mp, since the code address is the
2605 * key in the table, so if we free the code_mp first, another thread can grab the
2606 * same code address and replace our entry in the table.
2608 mono_jit_info_table_remove (domain
, ji
->ji
);
2611 mono_code_manager_destroy (ji
->code_mp
);
2616 mono_jit_search_all_backends_for_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**out_ji
)
2621 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
2623 ERROR_DECL (oerror
);
2625 /* Might be AOTed code */
2626 mono_class_init_internal (method
->klass
);
2627 code
= mono_aot_get_method (domain
, method
, oerror
);
2629 mono_error_assert_ok (oerror
);
2630 ji
= mono_jit_info_table_find (domain
, code
);
2632 if (!is_ok (oerror
))
2633 mono_error_cleanup (oerror
);
2635 /* Might be interpreted */
2636 ji
= mini_get_interp_callbacks ()->find_jit_info (domain
, method
);
2646 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2648 MonoDomain
*target_domain
;
2651 if (default_opt
& MONO_OPT_SHARED
)
2652 target_domain
= mono_get_root_domain ();
2654 target_domain
= domain
;
2656 info
= lookup_method (target_domain
, method
);
2658 /* We can't use a domain specific method in another domain */
2659 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2660 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2663 return info
->code_start
;
2672 static guint32 bisect_opt
= 0;
2673 static GHashTable
*bisect_methods_hash
= NULL
;
2676 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2679 char method_name
[2048];
2682 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2683 g_assert (bisect_methods_hash
);
2685 file
= fopen (method_list_filename
, "r");
2688 while (fgets (method_name
, sizeof (method_name
), file
)) {
2689 size_t len
= strlen (method_name
);
2691 g_assert (method_name
[len
- 1] == '\n');
2692 method_name
[len
- 1] = 0;
2693 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2695 g_assert (feof (file
));
2698 gboolean mono_do_single_method_regression
= FALSE
;
2699 guint32 mono_single_method_regression_opt
= 0;
2700 MonoMethod
*mono_current_single_method
;
2701 GSList
*mono_single_method_list
;
2702 GHashTable
*mono_single_method_hash
;
2705 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 opt
)
2709 if (bisect_methods_hash
) {
2710 char *name
= mono_method_full_name (method
, TRUE
);
2711 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2714 return opt
| bisect_opt
;
2716 if (!mono_do_single_method_regression
)
2718 if (!mono_current_single_method
) {
2719 if (!mono_single_method_hash
)
2720 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2721 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2722 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2723 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2727 if (method
== mono_current_single_method
)
2728 return mono_single_method_regression_opt
;
2733 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2735 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
2740 gpointer compiled_method
;
2741 gpointer runtime_invoke
;
2743 MonoDynCallInfo
*dyn_call_info
;
2744 MonoClass
*ret_box_class
;
2745 MonoMethodSignature
*sig
;
2746 gboolean gsharedvt_invoke
;
2747 gboolean use_interp
;
2748 gpointer
*wrapper_arg
;
2749 } RuntimeInvokeInfo
;
2751 static RuntimeInvokeInfo
*
2752 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, gboolean use_interp
, MonoError
*error
)
2755 RuntimeInvokeInfo
*info
= NULL
;
2756 RuntimeInvokeInfo
*ret
= NULL
;
2758 info
= g_new0 (RuntimeInvokeInfo
, 1);
2759 info
->compiled_method
= compiled_method
;
2760 info
->use_interp
= use_interp
;
2761 if (mono_llvm_only
&& method
->string_ctor
)
2762 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
2764 info
->sig
= mono_method_signature_internal (method
);
2766 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
2768 info
->vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2771 g_assert (info
->vtable
);
2773 MonoMethodSignature
*sig
;
2778 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2779 * in full-aot mode, so we use a slower, but more generic wrapper if
2780 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2782 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2783 if (!mono_llvm_only
&& (mono_aot_only
|| mini_debug_options
.dyn_runtime_invoke
)) {
2784 gboolean supported
= TRUE
;
2787 if (method
->string_ctor
)
2788 sig
= mono_marshal_get_string_ctor_signature (method
);
2790 for (i
= 0; i
< sig
->param_count
; ++i
) {
2791 MonoType
*t
= sig
->params
[i
];
2793 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2797 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
2801 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
2802 if (mini_debug_options
.dyn_runtime_invoke
)
2803 g_assert (info
->dyn_call_info
);
2808 ret_type
= sig
->ret
;
2809 switch (ret_type
->type
) {
2810 case MONO_TYPE_VOID
:
2822 case MONO_TYPE_BOOLEAN
:
2823 case MONO_TYPE_CHAR
:
2826 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2829 info
->ret_box_class
= mono_defaults
.int_class
;
2831 case MONO_TYPE_STRING
:
2832 case MONO_TYPE_CLASS
:
2833 case MONO_TYPE_ARRAY
:
2834 case MONO_TYPE_SZARRAY
:
2835 case MONO_TYPE_OBJECT
:
2837 case MONO_TYPE_GENERICINST
:
2838 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
2839 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2841 case MONO_TYPE_VALUETYPE
:
2842 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2845 g_assert_not_reached ();
2849 if (info
->use_interp
) {
2855 if (!info
->dyn_call_info
) {
2856 if (mono_llvm_only
) {
2857 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2858 g_assert_not_reached ();
2860 info
->gsharedvt_invoke
= TRUE
;
2861 if (!callee_gsharedvt
) {
2862 /* Invoke a gsharedvt out wrapper instead */
2863 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2864 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2866 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
2867 info
->wrapper_arg
[0] = mini_llvmonly_add_method_wrappers (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
2869 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2870 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2871 g_free (wrapper_sig
);
2873 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
2877 /* Gsharedvt methods can be invoked the same way */
2878 /* The out wrapper has the same signature as the compiled gsharedvt method */
2879 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2881 info
->wrapper_arg
= (gpointer
*)(mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
);
2883 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2884 g_free (wrapper_sig
);
2887 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
2900 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2902 MonoMethodSignature
*sig
= info
->sig
;
2903 MonoDomain
*domain
= mono_domain_get ();
2904 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2905 gpointer retval_ptr
;
2906 guint8 retval
[256];
2911 g_assert (info
->gsharedvt_invoke
);
2914 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2915 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2916 * signatures, so we only have to generate runtime invoke wrappers for these
2918 * This code also handles invocation of gsharedvt methods directly, no
2919 * out wrappers are used in that case.
2921 // allocate param_refs = param_count and args = param_count + hasthis + 2.
2922 int const param_count
= sig
->param_count
;
2923 gpointer
* const param_refs
= g_newa (gpointer
, param_count
* 2 + sig
->hasthis
+ 2);
2924 gpointer
* const args
= param_refs
+ param_count
;
2927 * The runtime invoke wrappers expects pointers to primitive types, so have to
2931 args
[pindex
++] = &obj
;
2932 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
2933 retval_ptr
= &retval
;
2934 args
[pindex
++] = &retval_ptr
;
2936 for (i
= 0; i
< sig
->param_count
; ++i
) {
2937 MonoType
*t
= sig
->params
[i
];
2939 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
2940 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
2941 guint8
*nullable_buf
;
2944 size
= mono_class_value_size (klass
, NULL
);
2945 nullable_buf
= g_alloca (size
);
2946 g_assert (nullable_buf
);
2948 /* The argument pointed to by params [i] is either a boxed vtype or null */
2949 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
2950 params
[i
] = nullable_buf
;
2953 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
2954 param_refs
[i
] = params
[i
];
2955 params
[i
] = &(param_refs
[i
]);
2957 args
[pindex
++] = ¶ms
[i
];
2959 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2960 args
[pindex
++] = &info
->wrapper_arg
;
2962 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2964 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
2968 if (sig
->ret
->type
!= MONO_TYPE_VOID
&& info
->ret_box_class
)
2969 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2971 return *(MonoObject
**)retval
;
2975 * mono_jit_runtime_invoke:
2976 * \param method: the method to invoke
2977 * \param obj: this pointer
2978 * \param params: array of parameter values.
2979 * \param exc: Set to the exception raised in the managed method.
2980 * \param error: error or caught exception object
2981 * If \p exc is NULL, \p error is thrown instead.
2982 * If coop is enabled, \p exc argument is ignored -
2983 * all exceptions are caught and propagated through \p error
2986 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2988 MonoMethod
*invoke
, *callee
;
2989 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2990 MonoDomain
*domain
= mono_domain_get ();
2991 MonoJitDomainInfo
*domain_info
;
2992 RuntimeInvokeInfo
*info
, *info2
;
2993 MonoJitInfo
*ji
= NULL
;
2994 gboolean callee_gsharedvt
= FALSE
;
2996 if (mono_ee_features
.force_use_interpreter
)
2997 return mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3003 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
3004 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3008 domain_info
= domain_jit_info (domain
);
3010 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
3013 if (mono_security_core_clr_enabled ()) {
3015 * This might be redundant since mono_class_vtable () already does this,
3016 * but keep it just in case for moonlight.
3018 mono_class_setup_vtable (method
->klass
);
3019 if (mono_class_has_failure (method
->klass
)) {
3020 mono_error_set_for_class_failure (error
, method
->klass
);
3022 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
3027 gpointer compiled_method
;
3030 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3031 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3033 * Array Get/Set/Address methods. The JIT implements them using inline code
3034 * inside the runtime invoke wrappers, so no need to compile them.
3036 if (mono_aot_only
) {
3038 * Call a wrapper, since the runtime invoke wrapper was not generated.
3040 MonoMethod
*wrapper
;
3042 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
3043 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
3050 gboolean use_interp
= FALSE
;
3053 compiled_method
= mono_jit_compile_method_jit_only (callee
, error
);
3054 if (!compiled_method
) {
3055 g_assert (!is_ok (error
));
3057 if (mono_use_interpreter
)
3062 if (mono_llvm_only
) {
3063 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
3064 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3065 if (callee_gsharedvt
)
3066 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
3069 if (!callee_gsharedvt
)
3070 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
3073 compiled_method
= NULL
;
3076 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, use_interp
, error
);
3080 mono_domain_lock (domain
);
3081 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
3082 mono_domain_unlock (domain
);
3090 * We need this here because mono_marshal_get_runtime_invoke can place
3091 * the helper method in System.Object and not the target class.
3093 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
3095 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3099 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3100 we always catch the exception and propagate it through the MonoError */
3101 gboolean catchExcInMonoError
=
3102 (exc
== NULL
) && mono_threads_are_safepoints_enabled ();
3103 MonoObject
*invoke_exc
= NULL
;
3104 if (catchExcInMonoError
)
3107 /* The wrappers expect this to be initialized to NULL */
3111 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3112 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
= NULL
;
3113 if (info
->dyn_call_info
) {
3114 if (!dyn_runtime_invoke
) {
3115 mono_domain_lock (domain
);
3117 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
3118 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method_jit_only (invoke
, error
);
3119 if (!dyn_runtime_invoke
&& mono_use_interpreter
) {
3120 info
->use_interp
= TRUE
;
3121 info
->dyn_call_info
= NULL
;
3122 } else if (!is_ok (error
)) {
3123 mono_domain_unlock (domain
);
3126 mono_domain_unlock (domain
);
3129 if (info
->dyn_call_info
) {
3130 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
3132 int i
, pindex
, buf_size
;
3134 guint8 retval
[256];
3136 /* Convert the arguments to the format expected by start_dyn_call () */
3137 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
3140 args
[pindex
++] = &obj
;
3141 for (i
= 0; i
< sig
->param_count
; ++i
) {
3142 MonoType
*t
= sig
->params
[i
];
3145 args
[pindex
++] = ¶ms
[i
];
3146 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
3147 args
[pindex
++] = ¶ms
[i
];
3149 args
[pindex
++] = params
[i
];
3153 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3155 buf_size
= mono_arch_dyn_call_get_buf_size (info
->dyn_call_info
);
3156 buf
= g_alloca (buf_size
);
3157 memset (buf
, 0, buf_size
);
3160 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
);
3162 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
3163 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
3165 if (catchExcInMonoError
&& *exc
!= NULL
) {
3166 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3170 if (info
->ret_box_class
)
3171 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3173 return *(MonoObject
**)retval
;
3179 if (info
->use_interp
) {
3180 result
= mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3181 return_val_if_nok (error
, NULL
);
3182 } else if (mono_llvm_only
) {
3183 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
3187 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3189 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
3191 if (catchExcInMonoError
&& *exc
!= NULL
) {
3192 ((MonoException
*)(*exc
))->caught_in_unmanaged
= TRUE
;
3193 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3198 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
3200 MonoException
*exc
= NULL
;
3203 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3204 MONO_SIG_HANDLER_GET_CONTEXT
;
3206 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3208 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3210 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3211 if (mono_arch_is_int_overflow (ctx
, info
))
3213 * The spec says this throws ArithmeticException, but MS throws the derived
3214 * OverflowException.
3216 exc
= mono_get_exception_overflow ();
3218 exc
= mono_get_exception_divide_by_zero ();
3220 exc
= mono_get_exception_divide_by_zero ();
3224 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3227 mono_sigctx_to_monoctx (ctx
, &mctx
);
3228 if (mono_dump_start ())
3229 mono_handle_native_crash ("SIGFPE", &mctx
, info
);
3230 if (mono_do_crash_chaining
) {
3231 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3236 mono_arch_handle_exception (ctx
, exc
);
3239 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3242 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler
)
3245 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3246 MONO_SIG_HANDLER_GET_CONTEXT
;
3248 if (mono_runtime_get_no_exec ())
3251 mono_sigctx_to_monoctx (ctx
, &mctx
);
3252 if (mono_dump_start ())
3253 mono_handle_native_crash ("SIGILL", &mctx
, info
);
3254 if (mono_do_crash_chaining
) {
3255 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3261 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3263 #define HAVE_SIG_INFO
3264 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3266 #ifdef MONO_SIG_HANDLER_DEBUG
3267 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3268 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3269 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3270 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3271 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3272 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3278 mono_is_addr_implicit_null_check (void *addr
)
3280 /* implicit null checks are only expected to work on the first page. larger
3281 * offsets are expected to have an explicit null check */
3282 return addr
<= GUINT_TO_POINTER (mono_target_pagesize ());
3285 // This function is separate from mono_sigsegv_signal_handler
3286 // so debug_fault_addr can be seen in debugger stacks.
3287 #ifdef MONO_SIG_HANDLER_DEBUG
3289 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug
)
3291 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3294 MonoJitInfo
*ji
= NULL
;
3295 MonoDomain
*domain
= mono_domain_get ();
3296 gpointer fault_addr
= NULL
;
3299 #if defined(HAVE_SIG_INFO) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3300 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3302 #ifdef HAVE_SIG_INFO
3303 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3307 MONO_SIG_HANDLER_GET_CONTEXT
;
3309 mono_sigctx_to_monoctx (ctx
, &mctx
);
3311 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3312 if (mono_arch_is_single_step_event (info
, ctx
)) {
3313 mini_get_dbg_callbacks ()->single_step_event (ctx
);
3315 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3316 mini_get_dbg_callbacks ()->breakpoint_hit (ctx
);
3321 #if defined(HAVE_SIG_INFO)
3322 #if !defined(HOST_WIN32)
3323 fault_addr
= info
->si_addr
;
3324 if (mono_aot_is_pagefault (info
->si_addr
)) {
3325 mono_aot_handle_pagefault (info
->si_addr
);
3330 /* The thread might no be registered with the runtime */
3331 if (!mono_domain_get () || !jit_tls
) {
3332 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3334 if (mono_dump_start())
3335 mono_handle_native_crash ("SIGSEGV", &mctx
, info
);
3336 if (mono_do_crash_chaining
) {
3337 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3344 ji
= mono_jit_info_table_find_internal (domain
, mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3346 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3347 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3350 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3351 fault_addr
= info
->si_addr
;
3352 if (fault_addr
== NULL
) {
3353 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3356 if (jit_tls
&& jit_tls
->stack_size
&&
3357 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3359 * The hard-guard page has been hit: there is not much we can do anymore
3360 * Print a hopefully clear message and abort.
3362 mono_handle_hard_stack_ovf (jit_tls
, ji
, &mctx
, (guint8
*)info
->si_addr
);
3363 g_assert_not_reached ();
3365 /* The original handler might not like that it is executed on an altstack... */
3366 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3370 /* exceptions-amd64.c handles the check itself */
3371 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3373 if (mono_is_addr_implicit_null_check (info
->si_addr
)) {
3374 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3376 // FIXME: This shouldn't run on the altstack
3377 if (mono_dump_start ())
3378 mono_handle_native_crash ("SIGSEGV", &mctx
, info
);
3385 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3388 if (mono_dump_start ())
3389 mono_handle_native_crash ("SIGSEGV", &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3391 if (mono_do_crash_chaining
) {
3392 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3397 if (mono_is_addr_implicit_null_check (fault_addr
)) {
3398 mono_arch_handle_exception (ctx
, NULL
);
3400 if (mono_dump_start ())
3401 mono_handle_native_crash ("SIGSEGV", &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3406 #ifdef MONO_SIG_HANDLER_DEBUG
3408 // This function is separate from mono_sigsegv_signal_handler_debug
3409 // so debug_fault_addr can be seen in debugger stacks.
3410 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3413 gpointer
const debug_fault_addr
= (gpointer
)MONO_SIG_HANDLER_GET_INFO () ->ep
->ExceptionRecord
->ExceptionInformation
[1];
3414 #elif defined (HAVE_SIG_INFO)
3415 gpointer
const debug_fault_addr
= MONO_SIG_HANDLER_GET_INFO ()->si_addr
;
3417 #error No extra parameter is passed, not even 0, to avoid any confusion.
3419 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG
);
3422 #endif // MONO_SIG_HANDLER_DEBUG
3424 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3427 MONO_SIG_HANDLER_GET_CONTEXT
;
3429 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3431 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3433 mono_arch_handle_exception (ctx
, exc
);
3435 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3438 #ifndef DISABLE_REMOTING
3439 /* mono_jit_create_remoting_trampoline:
3440 * @method: pointer to the method info
3442 * Creates a trampoline which calls the remoting functions. This
3443 * is used in the vtable of transparent proxies.
3445 * Returns: a pointer to the newly created code
3448 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3451 guint8
*addr
= NULL
;
3455 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature_internal (method
)->generic_param_count
) {
3456 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3460 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3461 (mono_method_signature_internal (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3462 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
, error
);
3465 return_val_if_nok (error
, NULL
);
3466 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3467 return_val_if_nok (error
, NULL
);
3468 return mono_get_addr_from_ftnptr (addr
);
3472 static G_GNUC_UNUSED
void
3473 no_imt_trampoline (void)
3475 g_assert_not_reached ();
3478 static G_GNUC_UNUSED
void
3479 no_vcall_trampoline (void)
3481 g_assert_not_reached ();
3484 static gpointer
*vtable_trampolines
;
3485 static int vtable_trampolines_size
;
3488 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3490 int index
= slot_index
+ MONO_IMT_SIZE
;
3493 return mini_llvmonly_get_vtable_trampoline (vt
, slot_index
, index
);
3495 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3496 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3498 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3502 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3503 while (new_size
<= index
)
3505 new_table
= g_new0 (gpointer
, new_size
);
3507 if (vtable_trampolines
)
3508 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3509 g_free (vtable_trampolines
);
3510 mono_memory_barrier ();
3511 vtable_trampolines
= (void **)new_table
;
3512 vtable_trampolines_size
= new_size
;
3517 if (!vtable_trampolines
[index
])
3518 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3519 return vtable_trampolines
[index
];
3523 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3525 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3529 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3534 gpointer
*imt
= (gpointer
*)vt
;
3535 imt
-= MONO_IMT_SIZE
;
3537 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3541 create_delegate_method_ptr (MonoMethod
*method
, MonoError
*error
)
3545 if (method_is_dynamic (method
)) {
3546 /* Creating a trampoline would leak memory */
3547 func
= mono_compile_method_checked (method
, error
);
3548 return_val_if_nok (error
, NULL
);
3550 gpointer trampoline
= mono_runtime_create_jump_trampoline (mono_domain_get (), method
, TRUE
, error
);
3551 return_val_if_nok (error
, NULL
);
3552 func
= mono_create_ftnptr (mono_domain_get (), trampoline
);
3558 mini_init_delegate (MonoDelegateHandle delegate
, MonoError
*error
)
3560 MonoDelegate
*del
= MONO_HANDLE_RAW (delegate
);
3562 if (mono_use_interpreter
) {
3563 mini_get_interp_callbacks ()->init_delegate (del
, error
);
3564 return_if_nok (error
);
3567 if (mono_llvm_only
) {
3568 g_assert (del
->method
);
3569 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3570 del
->method_ptr
= mini_llvmonly_load_method_delegate (del
->method
, FALSE
, FALSE
, &del
->extra_arg
, error
);
3571 } else if (!del
->method_ptr
) {
3572 del
->method_ptr
= create_delegate_method_ptr (del
->method
, error
);
3573 return_if_nok (error
);
3578 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3582 abs_offset
= offset
;
3584 abs_offset
= - abs_offset
;
3585 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ TARGET_SIZEOF_VOID_P
);
3589 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3591 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3594 static guint8
**cache
= NULL
;
3595 static int cache_size
= 0;
3600 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3603 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3604 is_interface
= mono_class_is_interface (method
->klass
);
3605 load_imt_reg
= is_virtual_generic
|| is_interface
;
3608 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
3610 offset
= MONO_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
3612 idx
= (offset
/ TARGET_SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3613 g_assert (idx
>= 0);
3615 /* Resize the cache to idx + 1 */
3616 if (cache_size
< idx
+ 1) {
3618 if (cache_size
< idx
+ 1) {
3620 int new_cache_size
= idx
+ 1;
3622 new_cache
= g_new0 (guint8
*, new_cache_size
);
3624 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3627 mono_memory_barrier ();
3629 cache_size
= new_cache_size
;
3637 /* FIXME Support more cases */
3638 if (mono_ee_features
.use_aot_trampolines
) {
3639 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3640 g_assert (cache
[idx
]);
3642 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3648 * mini_parse_debug_option:
3649 * @option: The option to parse.
3651 * Parses debug options for the mono runtime. The options are the same as for
3652 * the MONO_DEBUG environment variable.
3656 mini_parse_debug_option (const char *option
)
3658 // Empty string is ok as consequence of appending ",foo"
3659 // without first checking for empty.
3663 if (!strcmp (option
, "handle-sigint"))
3664 mini_debug_options
.handle_sigint
= TRUE
;
3665 else if (!strcmp (option
, "keep-delegates"))
3666 mini_debug_options
.keep_delegates
= TRUE
;
3667 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3668 mini_debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3669 else if (!strcmp (option
, "collect-pagefault-stats"))
3670 mini_debug_options
.collect_pagefault_stats
= TRUE
;
3671 else if (!strcmp (option
, "break-on-unverified"))
3672 mini_debug_options
.break_on_unverified
= TRUE
;
3673 else if (!strcmp (option
, "no-gdb-backtrace"))
3674 mini_debug_options
.no_gdb_backtrace
= TRUE
;
3675 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
3676 mini_debug_options
.suspend_on_native_crash
= TRUE
;
3677 else if (!strcmp (option
, "suspend-on-exception"))
3678 mini_debug_options
.suspend_on_exception
= TRUE
;
3679 else if (!strcmp (option
, "suspend-on-unhandled"))
3680 mini_debug_options
.suspend_on_unhandled
= TRUE
;
3681 else if (!strcmp (option
, "dont-free-domains"))
3682 mono_dont_free_domains
= TRUE
;
3683 else if (!strcmp (option
, "dyn-runtime-invoke"))
3684 mini_debug_options
.dyn_runtime_invoke
= TRUE
;
3685 else if (!strcmp (option
, "gdb"))
3686 mini_debug_options
.gdb
= TRUE
;
3687 else if (!strcmp (option
, "lldb"))
3688 mini_debug_options
.lldb
= TRUE
;
3689 else if (!strcmp (option
, "llvm-disable-self-init"))
3690 mini_debug_options
.llvm_disable_self_init
= TRUE
;
3691 else if (!strcmp (option
, "llvm-disable-inlining"))
3692 mini_debug_options
.llvm_disable_inlining
= TRUE
;
3693 else if (!strcmp (option
, "llvm-disable-implicit-null-checks"))
3694 mini_debug_options
.llvm_disable_implicit_null_checks
= TRUE
;
3695 else if (!strcmp (option
, "explicit-null-checks"))
3696 mini_debug_options
.explicit_null_checks
= TRUE
;
3697 else if (!strcmp (option
, "gen-seq-points"))
3698 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
3699 else if (!strcmp (option
, "gen-compact-seq-points"))
3700 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3701 else if (!strcmp (option
, "no-compact-seq-points"))
3702 mini_debug_options
.no_seq_points_compact_data
= TRUE
;
3703 else if (!strcmp (option
, "single-imm-size"))
3704 mini_debug_options
.single_imm_size
= TRUE
;
3705 else if (!strcmp (option
, "init-stacks"))
3706 mini_debug_options
.init_stacks
= TRUE
;
3707 else if (!strcmp (option
, "casts"))
3708 mini_debug_options
.better_cast_details
= TRUE
;
3709 else if (!strcmp (option
, "soft-breakpoints"))
3710 mini_debug_options
.soft_breakpoints
= TRUE
;
3711 else if (!strcmp (option
, "check-pinvoke-callconv"))
3712 mini_debug_options
.check_pinvoke_callconv
= TRUE
;
3713 else if (!strcmp (option
, "use-fallback-tls"))
3714 mini_debug_options
.use_fallback_tls
= TRUE
;
3715 else if (!strcmp (option
, "debug-domain-unload"))
3716 mono_enable_debug_domain_unload (TRUE
);
3717 else if (!strcmp (option
, "partial-sharing"))
3718 mono_set_partial_sharing_supported (TRUE
);
3719 else if (!strcmp (option
, "align-small-structs"))
3720 mono_align_small_structs
= TRUE
;
3721 else if (!strcmp (option
, "native-debugger-break"))
3722 mini_debug_options
.native_debugger_break
= TRUE
;
3723 else if (!strcmp (option
, "disable_omit_fp"))
3724 mini_debug_options
.disable_omit_fp
= TRUE
;
3725 // This is an internal testing feature.
3726 // Every tail. encountered is required to be optimized.
3728 else if (!strcmp (option
, "test-tailcall-require"))
3729 mini_debug_options
.test_tailcall_require
= TRUE
;
3730 else if (!strcmp (option
, "verbose-gdb"))
3731 mini_debug_options
.verbose_gdb
= TRUE
;
3732 else if (!strcmp (option
, "clr-memory-model"))
3733 // FIXME Kill this debug flag
3734 mini_debug_options
.weak_memory_model
= FALSE
;
3735 else if (!strcmp (option
, "weak-memory-model"))
3736 mini_debug_options
.weak_memory_model
= TRUE
;
3737 else if (!strncmp (option
, "thread-dump-dir=", 16))
3738 mono_set_thread_dump_dir(g_strdup(option
+ 16));
3739 else if (!strncmp (option
, "aot-skip=", 9)) {
3740 mini_debug_options
.aot_skip_set
= TRUE
;
3741 mini_debug_options
.aot_skip
= atoi (option
+ 9);
3749 mini_parse_debug_options (void)
3751 char *options
= g_getenv ("MONO_DEBUG");
3752 gchar
**args
, **ptr
;
3757 args
= g_strsplit (options
, ",", -1);
3760 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
3761 const char *arg
= *ptr
;
3763 if (!mini_parse_debug_option (arg
)) {
3764 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
3765 // test-tailcall-require is also accepted but not documented.
3766 // empty string is also accepted and ignored as a consequence
3767 // of appending ",foo" without checking for empty.
3768 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");
3777 mini_get_debug_options (void)
3779 return &mini_debug_options
;
3783 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
3785 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3786 gpointer
* desc
= NULL
;
3788 if ((desc
= (gpointer
*)g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
3790 #if defined(__mono_ppc64__)
3791 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
3797 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
3805 mini_get_addr_from_ftnptr (gpointer descr
)
3807 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3808 return *(gpointer
*)descr
;
3815 register_jit_stats (void)
3817 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
3818 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
3819 mono_counters_register ("Methods from AOT+LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot_llvm
);
3820 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
3821 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
3822 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_interp
);
3823 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_method_to_ir
);
3824 mono_counters_register ("JIT/liveness_handle_exception_clauses", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_liveness_handle_exception_clauses
);
3825 mono_counters_register ("JIT/handle_out_of_line_bblock", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_out_of_line_bblock
);
3826 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_long_opts
);
3827 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_typechecks
);
3828 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop
);
3829 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_emulate_ops
);
3830 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_optimize_branches
);
3831 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_global_vregs
);
3832 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce
);
3833 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_alias_analysis
);
3834 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_if_conversion
);
3835 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_bb_ordering
);
3836 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_compile_dominator_info
);
3837 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_compute_natural_loops
);
3838 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_insert_safepoints
);
3839 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_compute
);
3840 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_cprop
);
3841 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_deadce
);
3842 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_perform_abc_removal
);
3843 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_remove
);
3844 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop2
);
3845 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_global_vregs2
);
3846 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce2
);
3847 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_optimize_branches2
);
3848 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_vtype_opts
);
3849 mono_counters_register ("JIT/decompose_array_access_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_array_access_opts
);
3850 mono_counters_register ("JIT/liveness_handle_exception_clauses2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_liveness_handle_exception_clauses2
);
3851 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_analyze_liveness
);
3852 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_linear_scan
);
3853 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_arch_allocate_vars
);
3854 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_spill_global_vars
);
3855 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop3
);
3856 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce3
);
3857 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_codegen
);
3858 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_create_jit_info
);
3859 mono_counters_register ("JIT/gc_create_gc_map", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_gc_create_gc_map
);
3860 mono_counters_register ("JIT/save_seq_point_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_save_seq_point_info
);
3861 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_time
);
3862 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.basic_blocks
);
3863 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.max_basic_blocks
);
3864 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocate_var
);
3865 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.code_reallocs
);
3866 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_code_size
);
3867 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_seq_points_size
);
3868 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlineable_methods
);
3869 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlined_methods
);
3870 mono_counters_register ("Regvars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.regvars
);
3871 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.locals_stack_size
);
3872 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_lookups
);
3873 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.cil_code_size
);
3874 mono_counters_register ("Native code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.native_code_size
);
3875 mono_counters_register ("Aliases found", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_found
);
3876 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_removed
);
3877 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.loads_eliminated
);
3878 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.stores_eliminated
);
3879 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.optimized_divisions
);
3882 static void runtime_invoke_info_free (gpointer value
);
3885 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
3887 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
3888 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
3890 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
3894 class_method_pair_hash (gconstpointer data
)
3896 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
3898 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
3902 mini_create_jit_domain_info (MonoDomain
*domain
)
3904 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
3906 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3907 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3908 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
3909 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3910 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
3911 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
3912 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3913 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
3914 mono_jit_code_hash_init (&info
->interp_code_hash
);
3916 domain
->runtime_info
= info
;
3920 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
3922 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
3923 g_slist_free ((GSList
*)jlist
->list
);
3927 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
3929 GSList
*list
= (GSList
*)value
;
3930 g_slist_free (list
);
3934 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
3936 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
3937 mono_code_manager_destroy (di
->code_mp
);
3942 runtime_invoke_info_free (gpointer value
)
3944 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
3946 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3947 if (info
->dyn_call_info
)
3948 mono_arch_dyn_call_free (info
->dyn_call_info
);
3954 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
3956 g_slist_free ((GSList
*)value
);
3960 mini_free_jit_domain_info (MonoDomain
*domain
)
3962 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3964 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
3965 g_hash_table_destroy (info
->jump_target_hash
);
3966 if (info
->jump_target_got_slot_hash
) {
3967 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
3968 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
3970 if (info
->dynamic_code_hash
) {
3971 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
3972 g_hash_table_destroy (info
->dynamic_code_hash
);
3974 g_hash_table_destroy (info
->method_code_hash
);
3975 g_hash_table_destroy (info
->jump_trampoline_hash
);
3976 g_hash_table_destroy (info
->jit_trampoline_hash
);
3977 g_hash_table_destroy (info
->delegate_trampoline_hash
);
3978 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
3979 g_hash_table_destroy (info
->mrgctx_hash
);
3980 g_hash_table_destroy (info
->method_rgctx_hash
);
3981 g_hash_table_destroy (info
->interp_method_pointer_hash
);
3982 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
3983 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
3984 g_hash_table_destroy (info
->seq_points
);
3985 g_hash_table_destroy (info
->arch_seq_points
);
3986 if (info
->agent_info
)
3987 mini_get_dbg_callbacks ()->free_domain_info (domain
);
3988 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
3989 if (info
->llvm_jit_callees
) {
3990 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
3991 g_hash_table_destroy (info
->llvm_jit_callees
);
3993 mono_internal_hash_table_destroy (&info
->interp_code_hash
);
3995 mono_llvm_free_domain_info (domain
);
3998 g_free (domain
->runtime_info
);
3999 domain
->runtime_info
= NULL
;
4004 llvm_init_inner (void)
4006 if (!mono_llvm_load (NULL
))
4017 * Load and initialize LLVM support.
4018 * Return TRUE on success.
4021 mini_llvm_init (void)
4024 static gboolean llvm_inited
;
4025 static gboolean init_result
;
4027 mono_loader_lock_if_inited ();
4029 init_result
= llvm_init_inner ();
4032 mono_loader_unlock_if_inited ();
4040 mini_add_profiler_argument (const char *desc
)
4042 if (!profile_options
)
4043 profile_options
= g_ptr_array_new ();
4045 g_ptr_array_add (profile_options
, (gpointer
) desc
);
4049 const MonoEECallbacks
*mono_interp_callbacks_pointer
;
4052 mini_install_interp_callbacks (const MonoEECallbacks
*cbs
)
4054 mono_interp_callbacks_pointer
= cbs
;
4057 static MonoDebuggerCallbacks dbg_cbs
;
4060 mini_install_dbg_callbacks (MonoDebuggerCallbacks
*cbs
)
4062 g_assert (cbs
->version
== MONO_DBG_CALLBACKS_VERSION
);
4063 memcpy (&dbg_cbs
, cbs
, sizeof (MonoDebuggerCallbacks
));
4066 MonoDebuggerCallbacks
*
4067 mini_get_dbg_callbacks (void)
4073 mono_ee_api_version (void)
4075 return MONO_EE_API_VERSION
;
4079 mono_interp_entry_from_trampoline (gpointer ccontext
, gpointer imethod
)
4081 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext
, imethod
);
4085 mono_interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
4087 mini_get_interp_callbacks ()->to_native_trampoline (addr
, ccontext
);
4091 mini_is_interpreter_enabled (void)
4093 return mono_use_interpreter
;
4097 mono_get_runtime_build_version (void);
4100 mini_init (const char *filename
, const char *runtime_version
)
4105 MonoRuntimeCallbacks callbacks
;
4107 static const MonoThreadInfoRuntimeCallbacks ticallbacks
= {
4108 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK
, mono
)
4111 MONO_VES_INIT_BEGIN ();
4113 CHECKED_MONO_INIT ();
4115 #if defined(__linux__)
4116 if (access ("/proc/self/maps", F_OK
) != 0) {
4117 g_print ("Mono requires /proc to be mounted.\n");
4122 mono_interp_stub_init ();
4123 #ifndef DISABLE_INTERPRETER
4124 if (mono_use_interpreter
)
4125 mono_ee_interp_init (mono_interp_opts_string
);
4128 mono_debugger_agent_stub_init ();
4130 mono_debugger_agent_init ();
4134 mini_get_dbg_callbacks ()->parse_options (sdb_options
);
4136 mono_os_mutex_init_recursive (&jit_mutex
);
4138 mono_cross_helpers_run ();
4140 mono_counters_init ();
4144 mini_jit_init_job_control ();
4146 /* Happens when using the embedding interface */
4147 if (!default_opt_set
)
4148 default_opt
= mono_parse_default_optimizations (NULL
);
4150 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4152 mono_set_generic_sharing_vt_supported (TRUE
);
4155 mono_set_generic_sharing_vt_supported (TRUE
);
4158 mono_tls_init_runtime_keys ();
4160 if (!global_codeman
)
4161 global_codeman
= mono_code_manager_new ();
4163 memset (&callbacks
, 0, sizeof (callbacks
));
4164 callbacks
.create_ftnptr
= mini_create_ftnptr
;
4165 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
4166 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
4167 callbacks
.get_runtime_build_version
= mono_get_runtime_build_version
;
4168 callbacks
.set_cast_details
= mono_set_cast_details
;
4169 callbacks
.debug_log
= mini_get_dbg_callbacks ()->debug_log
;
4170 callbacks
.debug_log_is_enabled
= mini_get_dbg_callbacks ()->debug_log_is_enabled
;
4171 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
4172 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
4173 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
4174 callbacks
.init_delegate
= mini_init_delegate
;
4175 #define JIT_INVOKE_WORKS
4176 #ifdef JIT_INVOKE_WORKS
4177 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
4179 #define JIT_TRAMPOLINES_WORK
4180 #ifdef JIT_TRAMPOLINES_WORK
4181 callbacks
.compile_method
= mono_jit_compile_method
;
4182 callbacks
.create_jump_trampoline
= mono_create_jump_trampoline
;
4183 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
4184 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
4185 callbacks
.free_method
= mono_jit_free_method
;
4186 #ifndef DISABLE_REMOTING
4187 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
4190 #ifndef DISABLE_REMOTING
4191 if (mono_use_interpreter
)
4192 callbacks
.interp_get_remoting_invoke
= mini_get_interp_callbacks ()->get_remoting_invoke
;
4194 callbacks
.is_interpreter_enabled
= mini_is_interpreter_enabled
;
4195 callbacks
.get_weak_field_indexes
= mono_aot_get_weak_field_indexes
;
4197 #ifndef DISABLE_CRASH_REPORTING
4198 callbacks
.install_state_summarizer
= mini_register_sigterm_handler
;
4201 mono_install_callbacks (&callbacks
);
4204 mono_w32handle_init ();
4207 mono_thread_info_runtime_init (&ticallbacks
);
4209 if (g_hasenv ("MONO_DEBUG")) {
4210 mini_parse_debug_options ();
4213 mono_code_manager_init ();
4215 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4217 static const MonoCodeManagerCallbacks code_manager_callbacks
= {
4219 #undef MONO_CODE_MANAGER_CALLBACK
4220 #define MONO_CODE_MANAGER_CALLBACK(ret, name, sig) mono_arch_code_ ## name,
4221 MONO_CODE_MANAGER_CALLBACKS
4225 mono_code_manager_install_callbacks (&code_manager_callbacks
);
4230 mono_arch_cpu_init ();
4234 mono_unwind_init ();
4236 if (mini_debug_options
.lldb
|| g_hasenv ("MONO_LLDB")) {
4237 mono_lldb_init ("");
4238 mono_dont_free_domains
= TRUE
;
4241 #ifdef XDEBUG_ENABLED
4242 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
4244 mono_xdebug_init (mono_xdebug
);
4245 g_free (mono_xdebug
);
4246 /* So methods for multiple domains don't have the same address */
4247 mono_dont_free_domains
= TRUE
;
4248 mono_using_xdebug
= TRUE
;
4249 } else if (mini_debug_options
.gdb
) {
4250 mono_xdebug_init ((char*)"gdb");
4251 mono_dont_free_domains
= TRUE
;
4252 mono_using_xdebug
= TRUE
;
4257 if (mono_use_llvm
) {
4258 if (!mono_llvm_load (NULL
)) {
4259 mono_use_llvm
= FALSE
;
4260 fprintf (stderr
, "Mono Warning: llvm support could not be loaded.\n");
4267 mono_trampolines_init ();
4269 if (default_opt
& MONO_OPT_AOT
)
4272 mini_get_dbg_callbacks ()->init ();
4275 mono_wasm_debugger_init ();
4278 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4279 mono_set_generic_sharing_supported (TRUE
);
4282 mono_thread_info_signals_init ();
4284 mono_init_native_crash_info ();
4286 #ifndef MONO_CROSS_COMPILE
4287 mono_runtime_install_handlers ();
4289 mono_threads_install_cleanup (mini_thread_cleanup
);
4291 #ifdef JIT_TRAMPOLINES_WORK
4292 mono_install_create_domain_hook (mini_create_jit_domain_info
);
4293 mono_install_free_domain_hook (mini_free_jit_domain_info
);
4295 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
4296 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
4297 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
4299 mono_profiler_state
.context_enable
= mini_profiler_context_enable
;
4300 mono_profiler_state
.context_get_this
= mini_profiler_context_get_this
;
4301 mono_profiler_state
.context_get_argument
= mini_profiler_context_get_argument
;
4302 mono_profiler_state
.context_get_local
= mini_profiler_context_get_local
;
4303 mono_profiler_state
.context_get_result
= mini_profiler_context_get_result
;
4304 mono_profiler_state
.context_free_buffer
= mini_profiler_context_free_buffer
;
4306 if (profile_options
)
4307 for (guint i
= 0; i
< profile_options
->len
; i
++)
4308 mono_profiler_load ((const char *) g_ptr_array_index (profile_options
, i
));
4310 mono_profiler_started ();
4312 if (mini_debug_options
.collect_pagefault_stats
)
4313 mono_aot_set_make_unreadable (TRUE
);
4315 if (runtime_version
)
4316 domain
= mono_init_version (filename
, runtime_version
);
4318 domain
= mono_init_from_assembly (filename
, filename
);
4320 if (mono_aot_only
) {
4321 /* This helps catch code allocation requests */
4322 mono_code_manager_set_read_only (domain
->code_mp
);
4323 mono_marshal_use_aot_wrappers (TRUE
);
4326 if (mono_llvm_only
) {
4327 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline
);
4328 mono_set_always_build_imt_trampolines (TRUE
);
4329 } else if (mono_aot_only
) {
4330 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
4332 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
4335 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4336 mono_arch_finish_init ();
4338 /* This must come after mono_init () in the aot-only case */
4339 mono_exceptions_init ();
4341 /* This should come after mono_init () too */
4344 mono_create_icall_signatures ();
4346 register_jit_stats ();
4348 #define JIT_CALLS_WORK
4349 #ifdef JIT_CALLS_WORK
4350 /* Needs to be called here since register_jit_icall depends on it */
4351 mono_marshal_init ();
4353 mono_arch_register_lowlevel_calls ();
4357 mono_generic_sharing_init ();
4360 #ifdef MONO_ARCH_SIMD_INTRINSICS
4361 mono_simd_intrinsics_init ();
4364 mono_tasklets_init ();
4366 register_trampolines (domain
);
4368 if (mono_compile_aot
)
4370 * Avoid running managed code when AOT compiling, since the platform
4371 * might only support aot-only execution.
4373 mono_runtime_set_no_exec (TRUE
);
4375 mono_mem_account_register_counters ();
4377 #define JIT_RUNTIME_WORKS
4378 #ifdef JIT_RUNTIME_WORKS
4379 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
4380 mono_runtime_init_checked (domain
, (MonoThreadStartCB
)mono_thread_start_cb
, mono_thread_attach_cb
, error
);
4381 mono_error_assert_ok (error
);
4382 mono_thread_attach (domain
);
4383 MONO_PROFILER_RAISE (thread_name
, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4386 #ifdef ENABLE_EXPERIMENT_TIERED
4387 if (!mono_compile_aot
) {
4388 /* create compilation thread in background */
4389 mini_tiered_init ();
4393 if (mono_profiler_sampling_enabled ())
4394 mono_runtime_setup_stat_profiler ();
4396 MONO_PROFILER_RAISE (runtime_initialized
, ());
4398 MONO_VES_INIT_END ();
4404 register_icalls (void)
4406 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4407 ves_icall_get_frame_info
);
4408 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4409 ves_icall_get_trace
);
4410 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4411 mono_runtime_install_handlers
);
4412 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4413 mono_runtime_cleanup_handlers
);
4415 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4416 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4417 mini_get_dbg_callbacks ()->unhandled_exception
);
4421 * It's important that we pass `TRUE` as the last argument here, as
4422 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4423 * *did* emit a wrapper, we'd be looking at infinite recursion since
4424 * the wrapper would call the icall which would call the wrapper and
4427 register_icall (mono_profiler_raise_method_enter
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4428 register_icall (mono_profiler_raise_method_leave
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4429 register_icall (mono_profiler_raise_method_tail_call
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4430 register_icall (mono_profiler_raise_exception_clause
, mono_icall_sig_void_ptr_int_int_object
, TRUE
);
4432 register_icall (mono_trace_enter_method
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4433 register_icall (mono_trace_leave_method
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4434 g_assert (mono_get_lmf_addr
== mono_tls_get_lmf_addr
);
4435 register_icall (mono_jit_set_domain
, mono_icall_sig_void_ptr
, TRUE
);
4436 register_icall (mono_domain_get
, mono_icall_sig_ptr
, TRUE
);
4438 register_icall (mono_llvm_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4439 register_icall (mono_llvm_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4440 register_icall (mono_llvm_resume_exception
, mono_icall_sig_void
, TRUE
);
4441 register_icall (mono_llvm_match_exception
, mono_icall_sig_int_ptr_int_int_ptr_object
, TRUE
);
4442 register_icall (mono_llvm_clear_exception
, NULL
, TRUE
);
4443 register_icall (mono_llvm_load_exception
, mono_icall_sig_object
, TRUE
);
4444 register_icall (mono_llvm_throw_corlib_exception
, mono_icall_sig_void_int
, TRUE
);
4445 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4446 register_icall (mono_llvm_set_unhandled_exception_handler
, NULL
, TRUE
);
4448 // FIXME: This is broken
4450 register_icall (mono_debug_personality
, mono_icall_sig_int_int_int_ptr_ptr_ptr
, TRUE
);
4454 if (!mono_llvm_only
) {
4455 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4456 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4457 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception
, mono_icall_sig_void_ptr
, TRUE
);
4459 register_icall (mono_thread_get_undeniable_exception
, mono_icall_sig_object
, FALSE
);
4460 register_icall (ves_icall_thread_finish_async_abort
, mono_icall_sig_void
, FALSE
);
4461 register_icall (mono_thread_interruption_checkpoint
, mono_icall_sig_object
, FALSE
);
4462 register_icall (mono_thread_force_interruption_checkpoint_noraise
, mono_icall_sig_object
, FALSE
);
4464 register_icall (mono_threads_state_poll
, mono_icall_sig_void
, FALSE
);
4466 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4467 register_opcode_emulation (OP_LMUL
, __emul_lmul
, mono_icall_sig_long_long_long
, mono_llmult
, FALSE
);
4468 register_opcode_emulation (OP_LDIV
, __emul_ldiv
, mono_icall_sig_long_long_long
, mono_lldiv
, FALSE
);
4469 register_opcode_emulation (OP_LDIV_UN
, __emul_ldiv_un
, mono_icall_sig_long_long_long
, mono_lldiv_un
, FALSE
);
4470 register_opcode_emulation (OP_LREM
, __emul_lrem
, mono_icall_sig_long_long_long
, mono_llrem
, FALSE
);
4471 register_opcode_emulation (OP_LREM_UN
, __emul_lrem_un
, mono_icall_sig_long_long_long
, mono_llrem_un
, FALSE
);
4473 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4474 register_opcode_emulation (OP_LMUL_OVF_UN
, __emul_lmul_ovf_un
, mono_icall_sig_long_long_long
, mono_llmult_ovf_un
, FALSE
);
4475 register_opcode_emulation (OP_LMUL_OVF
, __emul_lmul_ovf
, mono_icall_sig_long_long_long
, mono_llmult_ovf
, FALSE
);
4478 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4479 register_opcode_emulation (OP_LSHL
, __emul_lshl
, mono_icall_sig_long_long_int32
, mono_lshl
, TRUE
);
4480 register_opcode_emulation (OP_LSHR
, __emul_lshr
, mono_icall_sig_long_long_int32
, mono_lshr
, TRUE
);
4481 register_opcode_emulation (OP_LSHR_UN
, __emul_lshr_un
, mono_icall_sig_long_long_int32
, mono_lshr_un
, TRUE
);
4484 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4485 register_opcode_emulation (OP_IDIV
, __emul_op_idiv
, mono_icall_sig_int32_int32_int32
, mono_idiv
, FALSE
);
4486 register_opcode_emulation (OP_IDIV_UN
, __emul_op_idiv_un
, mono_icall_sig_int32_int32_int32
, mono_idiv_un
, FALSE
);
4487 register_opcode_emulation (OP_IREM
, __emul_op_irem
, mono_icall_sig_int32_int32_int32
, mono_irem
, FALSE
);
4488 register_opcode_emulation (OP_IREM_UN
, __emul_op_irem_un
, mono_icall_sig_int32_int32_int32
, mono_irem_un
, FALSE
);
4491 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4492 register_opcode_emulation (OP_IMUL
, __emul_op_imul
, mono_icall_sig_int32_int32_int32
, mono_imul
, TRUE
);
4495 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4496 register_opcode_emulation (OP_IMUL_OVF
, __emul_op_imul_ovf
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf
, FALSE
);
4497 register_opcode_emulation (OP_IMUL_OVF_UN
, __emul_op_imul_ovf_un
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf_un
, FALSE
);
4500 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4501 register_opcode_emulation (OP_FDIV
, __emul_fdiv
, mono_icall_sig_double_double_double
, mono_fdiv
, FALSE
);
4504 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4505 register_opcode_emulation (OP_FCONV_TO_U8
, __emul_fconv_to_u8
, mono_icall_sig_ulong_double
, mono_fconv_u8_2
, FALSE
);
4506 register_opcode_emulation (OP_RCONV_TO_U8
, __emul_rconv_to_u8
, mono_icall_sig_ulong_float
, mono_rconv_u8
, FALSE
);
4508 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4509 register_opcode_emulation (OP_FCONV_TO_U4
, __emul_fconv_to_u4
, mono_icall_sig_uint32_double
, mono_fconv_u4_2
, FALSE
);
4510 register_opcode_emulation (OP_RCONV_TO_U4
, __emul_rconv_to_u4
, mono_icall_sig_uint32_float
, mono_rconv_u4
, FALSE
);
4512 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, __emul_fconv_to_ovf_i8
, mono_icall_sig_long_double
, mono_fconv_ovf_i8
, FALSE
);
4513 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, __emul_fconv_to_ovf_u8
, mono_icall_sig_ulong_double
, mono_fconv_ovf_u8
, FALSE
);
4514 register_opcode_emulation (OP_FCONV_TO_OVF_U8_UN
, __emul_fconv_to_ovf_u8_un
, mono_icall_sig_ulong_double
, mono_fconv_ovf_u8_un
, FALSE
);
4515 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, __emul_rconv_to_ovf_i8
, mono_icall_sig_long_float
, mono_rconv_ovf_i8
, FALSE
);
4516 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, __emul_rconv_to_ovf_u8
, mono_icall_sig_ulong_float
, mono_rconv_ovf_u8
, FALSE
);
4517 register_opcode_emulation (OP_RCONV_TO_OVF_U8_UN
, __emul_rconv_to_ovf_u8_un
, mono_icall_sig_ulong_float
, mono_rconv_ovf_u8_un
, FALSE
);
4519 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4520 register_opcode_emulation (OP_FCONV_TO_I8
, __emul_fconv_to_i8
, mono_icall_sig_long_double
, mono_fconv_i8
, FALSE
);
4521 register_opcode_emulation (OP_RCONV_TO_I8
, __emul_rconv_to_i8
, mono_icall_sig_long_float
, mono_rconv_i8
, FALSE
);
4524 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4525 register_opcode_emulation (OP_ICONV_TO_R_UN
, __emul_iconv_to_r_un
, mono_icall_sig_double_int32
, mono_conv_to_r8_un
, FALSE
);
4527 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4528 register_opcode_emulation (OP_LCONV_TO_R8
, __emul_lconv_to_r8
, mono_icall_sig_double_long
, mono_lconv_to_r8
, FALSE
);
4530 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4531 register_opcode_emulation (OP_LCONV_TO_R4
, __emul_lconv_to_r4
, mono_icall_sig_float_long
, mono_lconv_to_r4
, FALSE
);
4533 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4534 register_opcode_emulation (OP_LCONV_TO_R_UN
, __emul_lconv_to_r8_un
, mono_icall_sig_double_long
, mono_lconv_to_r8_un
, FALSE
);
4536 #ifdef MONO_ARCH_EMULATE_FREM
4537 register_opcode_emulation (OP_FREM
, __emul_frem
, mono_icall_sig_double_double_double
, mono_fmod
, FALSE
);
4538 register_opcode_emulation (OP_RREM
, __emul_rrem
, mono_icall_sig_float_float_float
, fmodf
, FALSE
);
4541 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4542 if (mono_arch_is_soft_float ()) {
4543 register_opcode_emulation (OP_FSUB
, __emul_fsub
, mono_icall_sig_double_double_double
, mono_fsub
, FALSE
);
4544 register_opcode_emulation (OP_FADD
, __emul_fadd
, mono_icall_sig_double_double_double
, mono_fadd
, FALSE
);
4545 register_opcode_emulation (OP_FMUL
, __emul_fmul
, mono_icall_sig_double_double_double
, mono_fmul
, FALSE
);
4546 register_opcode_emulation (OP_FNEG
, __emul_fneg
, mono_icall_sig_double_double
, mono_fneg
, FALSE
);
4547 register_opcode_emulation (OP_ICONV_TO_R8
, __emul_iconv_to_r8
, mono_icall_sig_double_int32
, mono_conv_to_r8
, FALSE
);
4548 register_opcode_emulation (OP_ICONV_TO_R4
, __emul_iconv_to_r4
, mono_icall_sig_double_int32
, mono_conv_to_r4
, FALSE
);
4549 register_opcode_emulation (OP_FCONV_TO_R4
, __emul_fconv_to_r4
, mono_icall_sig_double_double
, mono_fconv_r4
, FALSE
);
4550 register_opcode_emulation (OP_FCONV_TO_I1
, __emul_fconv_to_i1
, mono_icall_sig_int8_double
, mono_fconv_i1
, FALSE
);
4551 register_opcode_emulation (OP_FCONV_TO_I2
, __emul_fconv_to_i2
, mono_icall_sig_int16_double
, mono_fconv_i2
, FALSE
);
4552 register_opcode_emulation (OP_FCONV_TO_I4
, __emul_fconv_to_i4
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4553 register_opcode_emulation (OP_FCONV_TO_U1
, __emul_fconv_to_u1
, mono_icall_sig_uint8_double
, mono_fconv_u1
, FALSE
);
4554 register_opcode_emulation (OP_FCONV_TO_U2
, __emul_fconv_to_u2
, mono_icall_sig_uint16_double
, mono_fconv_u2
, FALSE
);
4556 #if TARGET_SIZEOF_VOID_P == 4
4557 register_opcode_emulation (OP_FCONV_TO_I
, __emul_fconv_to_i
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4560 register_opcode_emulation (OP_FBEQ
, __emul_fcmp_eq
, mono_icall_sig_uint32_double_double
, mono_fcmp_eq
, FALSE
);
4561 register_opcode_emulation (OP_FBLT
, __emul_fcmp_lt
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt
, FALSE
);
4562 register_opcode_emulation (OP_FBGT
, __emul_fcmp_gt
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt
, FALSE
);
4563 register_opcode_emulation (OP_FBLE
, __emul_fcmp_le
, mono_icall_sig_uint32_double_double
, mono_fcmp_le
, FALSE
);
4564 register_opcode_emulation (OP_FBGE
, __emul_fcmp_ge
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge
, FALSE
);
4565 register_opcode_emulation (OP_FBNE_UN
, __emul_fcmp_ne_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ne_un
, FALSE
);
4566 register_opcode_emulation (OP_FBLT_UN
, __emul_fcmp_lt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt_un
, FALSE
);
4567 register_opcode_emulation (OP_FBGT_UN
, __emul_fcmp_gt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt_un
, FALSE
);
4568 register_opcode_emulation (OP_FBLE_UN
, __emul_fcmp_le_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_le_un
, FALSE
);
4569 register_opcode_emulation (OP_FBGE_UN
, __emul_fcmp_ge_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge_un
, FALSE
);
4571 register_opcode_emulation (OP_FCEQ
, __emul_fcmp_ceq
, mono_icall_sig_uint32_double_double
, mono_fceq
, FALSE
);
4572 register_opcode_emulation (OP_FCGT
, __emul_fcmp_cgt
, mono_icall_sig_uint32_double_double
, mono_fcgt
, FALSE
);
4573 register_opcode_emulation (OP_FCGT_UN
, __emul_fcmp_cgt_un
, mono_icall_sig_uint32_double_double
, mono_fcgt_un
, FALSE
);
4574 register_opcode_emulation (OP_FCLT
, __emul_fcmp_clt
, mono_icall_sig_uint32_double_double
, mono_fclt
, FALSE
);
4575 register_opcode_emulation (OP_FCLT_UN
, __emul_fcmp_clt_un
, mono_icall_sig_uint32_double_double
, mono_fclt_un
, FALSE
);
4577 register_icall (mono_fload_r4
, mono_icall_sig_double_ptr
, FALSE
);
4578 register_icall (mono_fstore_r4
, mono_icall_sig_void_double_ptr
, FALSE
);
4579 register_icall (mono_fload_r4_arg
, mono_icall_sig_uint32_double
, FALSE
);
4580 register_icall (mono_isfinite_double
, mono_icall_sig_int32_double
, FALSE
);
4583 register_icall (mono_ckfinite
, mono_icall_sig_double_double
, FALSE
);
4585 #ifdef COMPRESSED_INTERFACE_BITMAP
4586 register_icall (mono_class_interface_match
, mono_icall_sig_uint32_ptr_int32
, TRUE
);
4589 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4590 #if SIZEOF_REGISTER == 4
4591 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_uint32_double
, mono_fconv_u4
, TRUE
);
4593 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_ulong_double
, mono_fconv_u8
, TRUE
);
4596 /* other jit icalls */
4597 register_icall (ves_icall_mono_delegate_ctor
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4598 register_icall (ves_icall_mono_delegate_ctor_interp
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4599 register_icall (mono_class_static_field_address
,
4600 mono_icall_sig_ptr_ptr_ptr
, FALSE
);
4601 register_icall (mono_ldtoken_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4602 register_icall (mono_ldtoken_wrapper_generic_shared
,
4603 mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4604 register_icall (mono_get_special_static_data
, mono_icall_sig_ptr_int
, FALSE
);
4605 register_icall (ves_icall_mono_ldstr
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4606 register_icall (mono_helper_stelem_ref_check
, mono_icall_sig_void_object_object
, FALSE
);
4607 register_icall (ves_icall_object_new
, mono_icall_sig_object_ptr_ptr
, FALSE
);
4608 register_icall (ves_icall_object_new_specific
, mono_icall_sig_object_ptr
, FALSE
);
4609 register_icall (ves_icall_array_new
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4610 register_icall (ves_icall_array_new_specific
, mono_icall_sig_object_ptr_int32
, FALSE
);
4611 register_icall (ves_icall_runtime_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4612 register_icall (mono_ldftn
, mono_icall_sig_ptr_ptr
, FALSE
);
4613 register_icall (mono_ldvirtfn
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4614 register_icall (mono_ldvirtfn_gshared
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4615 register_icall (mono_helper_compile_generic_method
, mono_icall_sig_ptr_object_ptr_ptr
, FALSE
);
4616 register_icall (mono_helper_ldstr
, mono_icall_sig_object_ptr_int
, FALSE
);
4617 register_icall (mono_helper_ldstr_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4618 register_icall (mono_helper_newobj_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4619 register_icall (mono_value_copy_internal
, mono_icall_sig_void_ptr_ptr_ptr
, FALSE
);
4620 register_icall (mono_object_castclass_unbox
, mono_icall_sig_object_object_ptr
, FALSE
);
4621 register_icall (mono_break
, NULL
, TRUE
);
4622 register_icall (mono_create_corlib_exception_0
, mono_icall_sig_object_int
, TRUE
);
4623 register_icall (mono_create_corlib_exception_1
, mono_icall_sig_object_int_object
, TRUE
);
4624 register_icall (mono_create_corlib_exception_2
, mono_icall_sig_object_int_object_object
, TRUE
);
4625 register_icall (mono_array_new_1
, mono_icall_sig_object_ptr_int
, FALSE
);
4626 register_icall (mono_array_new_2
, mono_icall_sig_object_ptr_int_int
, FALSE
);
4627 register_icall (mono_array_new_3
, mono_icall_sig_object_ptr_int_int_int
, FALSE
);
4628 register_icall (mono_array_new_4
, mono_icall_sig_object_ptr_int_int_int_int
, FALSE
);
4629 register_icall (mono_array_new_n_icall
, mono_icall_sig_object_ptr_int_ptr
, FALSE
);
4630 register_icall (mono_get_native_calli_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4631 register_icall (mono_resume_unwind
, mono_icall_sig_void_ptr
, TRUE
);
4632 register_icall (mono_gsharedvt_constrained_call
, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr
, FALSE
);
4633 register_icall (mono_gsharedvt_value_copy
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4635 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4636 MonoRangeCopyFunction
const mono_gc_wbarrier_range_copy
= mono_gc_get_range_copy_func ();
4637 register_icall_no_wrapper (mono_gc_wbarrier_range_copy
, mono_icall_sig_void_ptr_ptr_int
);
4639 register_icall (mono_object_castclass_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4640 register_icall (mono_object_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4641 register_icall (mono_generic_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4642 register_icall (mono_fill_class_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4643 register_icall (mono_fill_method_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4645 register_dyn_icall (mini_get_dbg_callbacks ()->user_break
, mono_debugger_agent_user_break
, mono_icall_sig_void
, FALSE
);
4647 register_icall (mini_llvm_init_method
, mono_icall_sig_void_ptr_int
, TRUE
);
4648 register_icall (mini_llvm_init_gshared_method_this
, mono_icall_sig_void_ptr_int_object
, TRUE
);
4649 register_icall (mini_llvm_init_gshared_method_mrgctx
, mono_icall_sig_void_ptr_int_ptr
, TRUE
);
4650 register_icall (mini_llvm_init_gshared_method_vtable
, mono_icall_sig_void_ptr_int_ptr
, TRUE
);
4652 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4653 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4654 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4655 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4656 /* This needs a wrapper so it can have a preserveall cconv */
4657 register_icall (mini_llvmonly_init_vtable_slot
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4658 register_icall (mini_llvmonly_init_delegate
, mono_icall_sig_void_object
, TRUE
);
4659 register_icall (mini_llvmonly_init_delegate_virtual
, mono_icall_sig_void_object_object_ptr
, TRUE
);
4660 register_icall (mini_llvmonly_throw_nullref_exception
, mono_icall_sig_void
, TRUE
);
4662 register_icall (mono_get_assembly_object
, mono_icall_sig_object_ptr
, TRUE
);
4663 register_icall (mono_get_method_object
, mono_icall_sig_object_ptr
, TRUE
);
4664 register_icall (mono_throw_method_access
, mono_icall_sig_void_ptr_ptr
, FALSE
);
4665 register_icall (mono_throw_bad_image
, mono_icall_sig_void
, FALSE
);
4666 register_icall_no_wrapper (mono_dummy_jit_icall
, mono_icall_sig_void
);
4668 register_icall_with_wrapper (mono_monitor_enter_internal
, mono_icall_sig_int32_obj
);
4669 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, mono_icall_sig_void_obj_ptr
);
4670 register_icall_no_wrapper (mono_monitor_enter_fast
, mono_icall_sig_int_obj
);
4671 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, mono_icall_sig_int_obj_ptr
);
4674 register_icall (pthread_getspecific
, mono_icall_sig_ptr_ptr
, TRUE
);
4676 /* Register tls icalls */
4677 register_icall_no_wrapper (mono_tls_get_thread_extern
, mono_icall_sig_ptr
);
4678 register_icall_no_wrapper (mono_tls_get_jit_tls_extern
, mono_icall_sig_ptr
);
4679 register_icall_no_wrapper (mono_tls_get_domain_extern
, mono_icall_sig_ptr
);
4680 register_icall_no_wrapper (mono_tls_get_sgen_thread_info_extern
, mono_icall_sig_ptr
);
4681 register_icall_no_wrapper (mono_tls_get_lmf_addr_extern
, mono_icall_sig_ptr
);
4683 register_icall_no_wrapper (mono_interp_entry_from_trampoline
, mono_icall_sig_void_ptr_ptr
);
4684 register_icall_no_wrapper (mono_interp_to_native_trampoline
, mono_icall_sig_void_ptr_ptr
);
4686 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4687 mono_arch_register_icall ();
4691 MonoJitStats mono_jit_stats
= {0};
4694 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4695 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4697 MONO_NO_SANITIZE_THREAD
4699 print_jit_stats (void)
4701 if (mono_jit_stats
.enabled
) {
4702 g_print ("Mono Jit statistics\n");
4703 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/ 100.0,
4704 mono_jit_stats
.max_ratio_method
);
4705 g_print ("Biggest method: %" G_GINT32_FORMAT
" (%s)\n", mono_jit_stats
.biggest_method_size
,
4706 mono_jit_stats
.biggest_method
);
4708 g_print ("Delegates created: %" G_GINT32_FORMAT
"\n", mono_stats
.delegate_creations
);
4709 g_print ("Initialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.initialized_class_count
);
4710 g_print ("Used classes: %" G_GINT32_FORMAT
"\n", mono_stats
.used_class_count
);
4711 g_print ("Generic vtables: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_vtable_count
);
4712 g_print ("Methods: %" G_GINT32_FORMAT
"\n", mono_stats
.method_count
);
4713 g_print ("Static data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_static_data_size
);
4714 g_print ("VTable data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_vtable_size
);
4715 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4717 g_print ("\nInitialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_class_count
);
4718 g_print ("Inflated types: %" G_GINT32_FORMAT
"\n", mono_stats
.inflated_type_count
);
4719 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4721 g_print ("Sharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_sharable_methods
);
4722 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_unsharable_methods
);
4723 g_print ("Shared generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_shared_methods
);
4724 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.gsharedvt_methods
);
4726 g_print ("IMT tables size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_tables_size
);
4727 g_print ("IMT number of tables: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_tables
);
4728 g_print ("IMT number of methods: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_methods
);
4729 g_print ("IMT used slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_used_slots
);
4730 g_print ("IMT colliding slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_slots_with_collisions
);
4731 g_print ("IMT max collisions: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_max_collisions_in_slot
);
4732 g_print ("IMT methods at max col: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_method_count_when_max_collisions
);
4733 g_print ("IMT trampolines size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_trampolines_size
);
4735 g_print ("JIT info table inserts: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_insert_count
);
4736 g_print ("JIT info table removes: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_remove_count
);
4737 g_print ("JIT info table lookups: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_lookup_count
);
4739 g_free (mono_jit_stats
.max_ratio_method
);
4740 mono_jit_stats
.max_ratio_method
= NULL
;
4741 g_free (mono_jit_stats
.biggest_method
);
4742 mono_jit_stats
.biggest_method
= NULL
;
4746 #ifdef DISABLE_CLEANUP
4748 mini_cleanup (MonoDomain
*domain
)
4751 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, stdout
);
4755 mini_cleanup (MonoDomain
*domain
)
4757 if (mono_profiler_sampling_enabled ())
4758 mono_runtime_shutdown_stat_profiler ();
4760 MONO_PROFILER_RAISE (runtime_shutdown_begin
, ());
4763 mono_cominterop_release_all_rcws ();
4766 #ifndef MONO_CROSS_COMPILE
4768 * mono_domain_finalize () needs to be called early since it needs the
4769 * execution engine still fully working (it may invoke managed finalizers).
4771 mono_domain_finalize (domain
, 2000);
4774 /* This accesses metadata so needs to be called before runtime shutdown */
4777 #ifndef MONO_CROSS_COMPILE
4778 mono_runtime_cleanup (domain
);
4781 #ifndef ENABLE_NETCORE
4782 mono_threadpool_cleanup ();
4785 MONO_PROFILER_RAISE (runtime_shutdown_end
, ());
4787 mono_profiler_cleanup ();
4789 if (profile_options
)
4790 g_ptr_array_free (profile_options
, TRUE
);
4792 mono_icall_cleanup ();
4794 mono_runtime_cleanup_handlers ();
4796 #ifndef MONO_CROSS_COMPILE
4797 mono_domain_free (domain
, TRUE
);
4799 free_jit_tls_data (mono_tls_get_jit_tls ());
4803 mono_llvm_cleanup ();
4806 mono_aot_cleanup ();
4808 mono_trampolines_cleanup ();
4810 mono_unwind_cleanup ();
4812 mono_code_manager_destroy (global_codeman
);
4813 g_free (vtable_trampolines
);
4815 mini_jit_cleanup ();
4817 mini_get_interp_callbacks ()->cleanup ();
4819 mono_tramp_info_cleanup ();
4821 mono_arch_cleanup ();
4823 mono_generic_sharing_cleanup ();
4825 mono_cleanup_native_crash_info ();
4829 mono_trace_cleanup ();
4831 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, stdout
);
4833 if (mono_inject_async_exc_method
)
4834 mono_method_desc_free (mono_inject_async_exc_method
);
4836 mono_tls_free_keys ();
4838 mono_os_mutex_destroy (&jit_mutex
);
4840 mono_code_manager_cleanup ();
4843 mono_w32handle_cleanup ();
4849 mono_set_defaults (int verbose_level
, guint32 opts
)
4851 mini_verbose
= verbose_level
;
4852 mono_set_optimizations (opts
);
4856 mono_disable_optimizations (guint32 opts
)
4858 default_opt
&= ~opts
;
4862 mono_set_optimizations (guint32 opts
)
4865 default_opt_set
= TRUE
;
4866 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4867 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
4870 mono_set_generic_sharing_vt_supported (TRUE
);
4875 mono_set_verbose_level (guint32 level
)
4877 mini_verbose
= level
;
4881 mono_get_runtime_build_version (void)
4883 return FULL_VERSION
;
4887 * mono_get_runtime_build_info:
4888 * The returned string is owned by the caller. The returned string
4889 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4890 * \returns the runtime version + build date in string format.
4893 mono_get_runtime_build_info (void)
4895 if (mono_build_date
)
4896 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
4898 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
4902 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
4904 GHashTable
*assemblies
= (GHashTable
*)user_data
;
4905 MonoImage
*image
= mono_assembly_get_image_internal (ass
);
4906 MonoMethod
*method
, *invoke
;
4909 if (g_hash_table_lookup (assemblies
, ass
))
4912 g_hash_table_insert (assemblies
, ass
, ass
);
4914 if (mini_verbose
> 0)
4915 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
4917 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
4920 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, error
);
4922 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4925 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
4927 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
4931 if (mini_verbose
> 1) {
4932 char * desc
= mono_method_full_name (method
, TRUE
);
4933 g_print ("Compiling %d %s\n", count
, desc
);
4936 mono_compile_method_checked (method
, error
);
4937 if (!is_ok (error
)) {
4938 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4941 if (strcmp (method
->name
, "Finalize") == 0) {
4942 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4943 mono_compile_method_checked (invoke
, error
);
4944 mono_error_assert_ok (error
);
4946 #ifndef DISABLE_REMOTING
4947 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature_internal (method
)->hasthis
) {
4948 invoke
= mono_marshal_get_remoting_invoke_with_check (method
, error
);
4949 mono_error_assert_ok (error
);
4950 mono_compile_method_checked (invoke
, error
);
4951 mono_error_assert_ok (error
);
4956 /* Load and precompile referenced assemblies as well */
4957 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
4958 mono_assembly_load_reference (image
, i
);
4959 if (image
->references
[i
])
4960 mono_precompile_assembly (image
->references
[i
], assemblies
);
4964 void mono_precompile_assemblies ()
4966 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
4968 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
4970 g_hash_table_destroy (assemblies
);
4975 * Have to export this for AOT.
4978 mono_personality (void)
4981 g_assert_not_reached ();
4984 static MonoBreakPolicy
4985 always_insert_breakpoint (MonoMethod
*method
)
4987 return MONO_BREAK_POLICY_ALWAYS
;
4990 static MonoBreakPolicyFunc break_policy_func
= always_insert_breakpoint
;
4993 * mono_set_break_policy:
4994 * \param policy_callback the new callback function
4996 * Allow embedders to decide whether to actually obey breakpoint instructions
4997 * (both break IL instructions and \c Debugger.Break method calls), for example
4998 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4999 * untrusted or semi-trusted code.
5001 * \p policy_callback will be called every time a break point instruction needs to
5002 * be inserted with the method argument being the method that calls \c Debugger.Break
5003 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5004 * if it wants the breakpoint to not be effective in the given method.
5005 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5008 mono_set_break_policy (MonoBreakPolicyFunc policy_callback
)
5010 if (policy_callback
)
5011 break_policy_func
= policy_callback
;
5013 break_policy_func
= always_insert_breakpoint
;
5017 mini_should_insert_breakpoint (MonoMethod
*method
)
5019 switch (break_policy_func (method
)) {
5020 case MONO_BREAK_POLICY_ALWAYS
:
5022 case MONO_BREAK_POLICY_NEVER
:
5024 case MONO_BREAK_POLICY_ON_DBG
:
5025 g_warning ("mdb no longer supported");
5028 g_warning ("Incorrect value returned from break policy callback");
5033 // Custom handlers currently only implemented by Windows.
5036 mono_runtime_install_custom_handlers (const char *handlers
)
5042 mono_runtime_install_custom_handlers_usage (void)
5045 "Custom Handlers:\n"
5046 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5047 " separated list of available handlers to install.\n"
5049 "No handlers supported on current platform.\n");
5051 #endif /* HOST_WIN32 */