3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/assembly-internals.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/tokentype.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/metadata/threads.h>
41 #include <mono/metadata/appdomain.h>
42 #include <mono/metadata/debug-helpers.h>
43 #include <mono/metadata/domain-internals.h>
44 #include <mono/metadata/profiler-private.h>
45 #include <mono/metadata/mono-config.h>
46 #include <mono/metadata/environment.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/threads-types.h>
50 #include <mono/metadata/mempool-internals.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/runtime.h>
53 #include <mono/metadata/reflection-internals.h>
54 #include <mono/metadata/monitor.h>
55 #include <mono/metadata/icall-internals.h>
56 #include <mono/metadata/loader-internals.h>
57 #define MONO_MATH_DECLARE_ALL 1
58 #include <mono/utils/mono-math.h>
59 #include <mono/utils/mono-compiler.h>
60 #include <mono/utils/mono-counters.h>
61 #include <mono/utils/mono-error-internals.h>
62 #include <mono/utils/mono-logger-internals.h>
63 #include <mono/utils/mono-mmap.h>
64 #include <mono/utils/mono-path.h>
65 #include <mono/utils/mono-tls.h>
66 #include <mono/utils/mono-hwcap.h>
67 #include <mono/utils/dtrace.h>
68 #include <mono/utils/mono-signal-handler.h>
69 #include <mono/utils/mono-threads.h>
70 #include <mono/utils/mono-threads-coop.h>
71 #include <mono/utils/checked-build.h>
72 #include <mono/utils/mono-compiler.h>
73 #include <mono/utils/mono-proclib.h>
74 #include <mono/metadata/w32handle.h>
75 #include <mono/metadata/threadpool.h>
78 #include "seq-points.h"
84 #include "aot-compiler.h"
85 #include "aot-runtime.h"
86 #include "llvmonly-runtime.h"
88 #include "jit-icalls.h"
91 #include "mini-llvm.h"
92 #include "debugger-agent.h"
94 #include "mini-runtime.h"
95 #include "interp/interp.h"
97 #ifdef MONO_ARCH_LLVM_SUPPORTED
99 #include "mini-llvm-cpp.h"
100 #include "llvm-jit.h"
103 #include "mono/metadata/icall-signatures.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_interpreter
= FALSE
;
129 const char *mono_interp_opts_string
= NULL
;
131 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
132 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
133 static mono_mutex_t jit_mutex
;
135 static MonoCodeManager
*global_codeman
;
137 MonoDebugOptions mini_debug_options
;
140 #ifdef VALGRIND_JIT_REGISTER_MAP
141 int valgrind_register
;
143 GList
* mono_aot_paths
;
145 static GPtrArray
*profile_options
;
147 static GSList
*tramp_infos
;
148 GSList
*mono_interp_only_classes
;
150 static void register_icalls (void);
153 mono_running_on_valgrind (void)
156 if (RUNNING_ON_VALGRIND
){
157 #ifdef VALGRIND_JIT_REGISTER_MAP
158 valgrind_register
= TRUE
;
172 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
174 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
177 ud
->method
= (MonoMethod
*)key
;
182 mono_get_method_from_ip (void *ip
)
188 MonoDomain
*domain
= mono_domain_get ();
189 MonoDebugSourceLocation
*location
;
190 FindTrampUserData user_data
;
193 domain
= mono_get_root_domain ();
195 ji
= mono_jit_info_table_find_internal (domain
, ip
, TRUE
, TRUE
);
198 user_data
.method
= NULL
;
199 mono_domain_lock (domain
);
200 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
201 mono_domain_unlock (domain
);
202 if (user_data
.method
) {
203 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
204 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
210 } else if (ji
->is_trampoline
) {
211 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ji
->d
.tramp_info
->name
);
215 method
= jinfo_get_method (ji
);
216 method_name
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_IL
);
217 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
219 char *file_loc
= NULL
;
221 file_loc
= g_strdup_printf ("[%s :: %du]", location
->source_file
, location
->row
);
223 res
= g_strdup_printf (" %s [{%p} + 0x%x] %s (%p %p) [%p - %s]", method_name
, method
, (int)((char*)ip
- (char*)ji
->code_start
), file_loc
? file_loc
: "", ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, domain
, domain
->friendly_name
);
225 mono_debug_free_source_location (location
);
226 g_free (method_name
);
234 * \param ip an instruction pointer address
236 * This method is used from a debugger to get the name of the
237 * method at address \p ip. This routine is typically invoked from
238 * a debugger like this:
240 * (gdb) print mono_pmip ($pc)
242 * \returns the name of the method at address \p ip.
247 return mono_get_method_from_ip (ip
);
251 * mono_print_method_from_ip:
252 * \param ip an instruction pointer address
254 * This method is used from a debugger to get the name of the
255 * method at address \p ip.
257 * This prints the name of the method at address \p ip in the standard
258 * output. Unlike \c mono_pmip which returns a string, this routine
259 * prints the value on the standard output.
262 mono_print_method_from_ip (void *ip
)
266 MonoDebugSourceLocation
*source
;
267 MonoDomain
*domain
= mono_domain_get ();
268 MonoDomain
*target_domain
= mono_domain_get ();
269 FindTrampUserData user_data
;
270 MonoGenericSharingContext
*gsctx
;
271 const char *shared_type
;
274 domain
= mono_get_root_domain ();
275 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
276 if (ji
&& ji
->is_trampoline
) {
277 MonoTrampInfo
*tinfo
= ji
->d
.tramp_info
;
279 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
285 user_data
.method
= NULL
;
286 mono_domain_lock (domain
);
287 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
288 mono_domain_unlock (domain
);
290 if (user_data
.method
) {
291 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
292 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
297 g_print ("No method at %p\n", ip
);
301 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
302 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
304 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
307 if (gsctx
->is_gsharedvt
)
308 shared_type
= "gsharedvt ";
310 shared_type
= "gshared ";
313 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
);
316 g_print ("%s:%d\n", source
->source_file
, source
->row
);
319 mono_debug_free_source_location (source
);
324 * mono_method_same_domain:
326 * Determine whenever two compiled methods are in the same domain, thus
327 * the address of the callee can be embedded in the caller.
329 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
333 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
337 * If the call was made from domain-neutral to domain-specific
338 * code, we can't patch the call site.
340 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
343 cmethod
= jinfo_get_method (caller
);
344 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
345 (strstr (cmethod
->name
, "InvokeInDomain"))) {
346 /* The InvokeInDomain methods change the current appdomain */
354 * mono_global_codeman_reserve:
356 * Allocate code memory from the global code manager.
358 void *(mono_global_codeman_reserve
) (int size
)
363 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
365 if (!global_codeman
) {
366 /* This can happen during startup */
367 global_codeman
= mono_code_manager_new ();
368 return mono_code_manager_reserve (global_codeman
, size
);
372 ptr
= mono_code_manager_reserve (global_codeman
, size
);
378 /* The callback shouldn't take any locks */
380 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
383 mono_code_manager_foreach (global_codeman
, func
, user_data
);
388 * mono_create_unwind_op:
390 * Create an unwind op with the given parameters.
393 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
395 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
406 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
408 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
411 res
->has_context
= context
!= NULL
;
413 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
419 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
421 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
425 * mono_tramp_info_create:
427 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
428 * of JI, and UNWIND_OPS.
431 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
433 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
435 info
->name
= g_strdup (name
);
437 info
->code_size
= code_size
;
439 info
->unwind_ops
= unwind_ops
;
445 mono_tramp_info_free (MonoTrampInfo
*info
)
450 mono_free_unwind_info (info
->unwind_ops
);
451 if (info
->owns_uw_info
)
452 g_free (info
->uw_info
);
457 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
461 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
462 mono_jit_info_init (ji
, NULL
, info
->code
, info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
463 ji
->d
.tramp_info
= info
;
464 ji
->is_trampoline
= TRUE
;
466 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
468 mono_jit_info_table_add (domain
, ji
);
472 * mono_tramp_info_register:
474 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
479 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
487 domain
= mono_get_root_domain ();
490 copy
= mono_domain_alloc0 (domain
, sizeof (MonoTrampInfo
));
492 copy
= g_new0 (MonoTrampInfo
, 1);
494 copy
->code
= info
->code
;
495 copy
->code_size
= info
->code_size
;
496 copy
->name
= g_strdup (info
->name
);
498 if (info
->unwind_ops
) {
499 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
500 copy
->owns_uw_info
= TRUE
;
502 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
503 guint8
*temp
= copy
->uw_info
;
504 copy
->uw_info
= mono_domain_alloc (domain
, copy
->uw_info_len
);
505 memcpy (copy
->uw_info
, temp
, copy
->uw_info_len
);
509 /* Trampolines from aot have the unwind ops already encoded */
510 copy
->uw_info
= info
->uw_info
;
511 copy
->uw_info_len
= info
->uw_info_len
;
514 mono_save_trampoline_xdebug_info (info
);
515 mono_lldb_save_trampoline_info (info
);
517 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
519 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
523 /* If no root domain has been created yet, postpone the registration. */
525 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
527 } else if (copy
->uw_info
) {
528 /* Only register trampolines that have unwind infos */
529 register_trampoline_jit_info (domain
, copy
);
532 if (mono_jit_map_is_enabled ())
533 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
535 mono_tramp_info_free (info
);
539 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
541 mono_tramp_info_register_internal (info
, domain
, FALSE
);
545 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
547 mono_tramp_info_register_internal (info
, domain
, TRUE
);
551 mono_tramp_info_cleanup (void)
555 for (l
= tramp_infos
; l
; l
= l
->next
) {
556 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
558 mono_tramp_info_free (info
);
560 g_slist_free (tramp_infos
);
563 /* Register trampolines created before the root domain was created in the jit info tables */
565 register_trampolines (MonoDomain
*domain
)
569 for (l
= tramp_infos
; l
; l
= l
->next
) {
570 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
572 register_trampoline_jit_info (domain
, info
);
576 G_GNUC_UNUSED
static void
582 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
583 * Set a breakpoint in break_count () to break the last time <x> is done.
585 G_GNUC_UNUSED gboolean
586 mono_debug_count (void)
588 static int count
= 0, int_val
= 0;
589 static gboolean inited
, has_value
= FALSE
;
594 char *value
= g_getenv ("COUNT");
596 int_val
= atoi (value
);
606 if (count
== int_val
)
616 mono_icall_get_wrapper_method (MonoJitICallInfo
* callinfo
)
618 gboolean check_exc
= TRUE
;
620 if (!strcmp (callinfo
->name
, "mono_thread_interruption_checkpoint"))
621 /* This icall is used to check for exceptions, so don't check in the wrapper */
624 return mono_marshal_get_icall_wrapper (callinfo
, check_exc
);
628 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
632 gconstpointer addr
, trampoline
;
633 MonoDomain
*domain
= mono_get_root_domain ();
635 if (callinfo
->wrapper
)
636 return callinfo
->wrapper
;
638 wrapper
= mono_icall_get_wrapper_method (callinfo
);
641 addr
= mono_compile_method_checked (wrapper
, error
);
642 mono_error_assert_ok (error
);
643 mono_memory_barrier ();
644 callinfo
->wrapper
= addr
;
647 if (callinfo
->trampoline
)
648 return callinfo
->trampoline
;
649 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, error
);
650 mono_error_assert_ok (error
);
651 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
654 if (!callinfo
->trampoline
) {
655 mono_register_jit_icall_wrapper (callinfo
, trampoline
);
656 callinfo
->trampoline
= trampoline
;
658 mono_loader_unlock ();
660 return callinfo
->trampoline
;
665 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
667 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
670 static MonoJitDynamicMethodInfo
*
671 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
673 MonoJitDynamicMethodInfo
*res
;
675 if (domain_jit_info (domain
)->dynamic_code_hash
)
676 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
683 template <typename T
>
685 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, T func
, const char *symbol
, gboolean no_wrapper
)
688 register_opcode_emulation (int opcode
, MonoJitICallInfo
*jit_icall_info
, const char *name
, MonoMethodSignature
*sig
, gpointer func
, const char *symbol
, gboolean no_wrapper
)
692 mini_register_opcode_emulation (opcode
, jit_icall_info
, name
, sig
, func
, symbol
, no_wrapper
);
694 // FIXME ifdef in mini_register_opcode_emulation and just call it.
696 g_assert (!sig
->hasthis
);
697 g_assert (sig
->param_count
< 3);
699 mono_register_jit_icall_info (jit_icall_info
, func
, name
, sig
, no_wrapper
, symbol
);
703 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
704 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
707 * For JIT icalls implemented in C.
708 * NAME should be the same as the name of the C function whose address is FUNC.
709 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
710 * can't throw exceptions.
712 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
713 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
715 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
716 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
717 * must be extern "C".
719 #define register_icall(func, sig, avoid_wrapper) \
720 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
722 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
723 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
726 * Register an icall where FUNC is dynamically generated or otherwise not
727 * possible to link to it using NAME during AOT.
729 * func is an expression, such a local variable or a function call to get a function pointer.
730 * name is an identifier
732 * Providing func and name separately is what distinguishes "dyn" from regular.
734 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
736 #define register_dyn_icall(func, name, sig, save) \
737 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
742 MonoJitTlsData
*jit_tls
;
744 if ((jit_tls
= mono_tls_get_jit_tls ()))
747 * We do not assert here because this function can be called from
748 * mini-gc.c on a thread that has not executed any managed code, yet
749 * (the thread object allocation can trigger a collection).
755 mono_set_lmf (MonoLMF
*lmf
)
757 (*mono_get_lmf_addr ()) = lmf
;
761 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
763 MonoThreadInfo
*info
;
765 mono_tls_set_jit_tls (jit_tls
);
767 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
768 info
= mono_thread_info_current ();
770 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
774 mono_set_lmf_addr (MonoLMF
**lmf_addr
)
776 MonoThreadInfo
*info
;
778 mono_tls_set_lmf_addr (lmf_addr
);
780 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
781 info
= mono_thread_info_current ();
783 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
789 * Push an MonoLMFExt frame on the LMF stack.
792 mono_push_lmf (MonoLMFExt
*ext
)
796 lmf_addr
= mono_get_lmf_addr ();
798 ext
->lmf
.previous_lmf
= *lmf_addr
;
799 /* Mark that this is a MonoLMFExt */
800 ext
->lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
->lmf
.previous_lmf
) | 2);
802 mono_set_lmf ((MonoLMF
*)ext
);
808 * Pop the last frame from the LMF stack.
811 mono_pop_lmf (MonoLMF
*lmf
)
813 mono_set_lmf ((MonoLMF
*)(((gssize
)lmf
->previous_lmf
) & ~3));
817 * mono_jit_thread_attach:
819 * Called by Xamarin.Mac and other products. Attach thread to runtime if
820 * needed and switch to @domain.
822 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
824 * If the thread is newly-attached, put into GC Safe mode.
826 * @return the original domain which needs to be restored, or NULL.
829 mono_jit_thread_attach (MonoDomain
*domain
)
835 /* Happens when called from AOTed code which is only used in the root domain. */
836 domain
= mono_get_root_domain ();
841 attached
= mono_tls_get_jit_tls () != NULL
;
844 mono_thread_attach (domain
);
847 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
849 /* mono_jit_thread_attach is external-only and not called by
850 * the runtime on any of our own threads. So if we get here,
851 * the thread is running native code - leave it in GC Safe mode
852 * and leave it to the n2m invoke wrappers or MONO_API entry
853 * points to switch to GC Unsafe.
855 MONO_STACKDATA (stackdata
);
856 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata
);
859 orig
= mono_domain_get ();
861 mono_domain_set_fast (domain
, TRUE
);
863 return orig
!= domain
? orig
: NULL
;
867 * mono_jit_set_domain:
869 * Set domain to @domain if @domain is not null
872 mono_jit_set_domain (MonoDomain
*domain
)
874 g_assert (!mono_threads_is_blocking_transition_enabled ());
877 mono_domain_set_fast (domain
, TRUE
);
882 * \param obj exception object
883 * Abort the thread, print exception information and stack trace
886 mono_thread_abort (MonoObject
*obj
)
888 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
890 /* handle_remove should be eventually called for this thread, too
893 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
894 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
) ||
895 ((obj
->vtable
->klass
) == mono_class_try_get_appdomain_unloaded_exception_class () &&
896 mono_thread_info_current ()->runtime_thread
)) {
899 mono_invoke_unhandled_exception_hook (obj
);
903 static MonoJitTlsData
*
904 setup_jit_tls_data (gpointer stack_start
, MonoAbortFunction abort_func
)
906 MonoJitTlsData
*jit_tls
;
909 jit_tls
= mono_tls_get_jit_tls ();
913 jit_tls
= g_new0 (MonoJitTlsData
, 1);
915 jit_tls
->abort_func
= abort_func
;
916 jit_tls
->end_of_stack
= stack_start
;
918 mono_set_jit_tls (jit_tls
);
920 lmf
= g_new0 (MonoLMF
, 1);
921 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
923 jit_tls
->first_lmf
= lmf
;
925 mono_set_lmf_addr (&jit_tls
->lmf
);
929 #ifdef MONO_ARCH_HAVE_TLS_INIT
930 mono_arch_tls_init ();
933 mono_setup_altstack (jit_tls
);
939 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
941 //This happens during AOT cuz the thread is never attached
944 mono_arch_free_jit_tls_data (jit_tls
);
945 mono_free_altstack (jit_tls
);
947 g_free (jit_tls
->first_lmf
);
948 g_free (jit_tls
->interp_context
);
953 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
955 MonoThreadInfo
*thread
;
956 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
957 thread
= mono_thread_info_current_unchecked ();
959 thread
->jit_data
= jit_tls
;
961 mono_arch_cpu_init ();
964 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
967 mono_thread_abort_dummy (MonoObject
*obj
)
969 if (mono_thread_attach_aborted_cb
)
970 mono_thread_attach_aborted_cb (obj
);
972 mono_thread_abort (obj
);
976 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
978 MonoThreadInfo
*thread
;
979 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
980 thread
= mono_thread_info_current_unchecked ();
982 thread
->jit_data
= jit_tls
;
984 mono_arch_cpu_init ();
988 mini_thread_cleanup (MonoNativeThreadId tid
)
990 MonoJitTlsData
*jit_tls
= NULL
;
991 MonoThreadInfo
*info
;
993 info
= mono_thread_info_current_unchecked ();
995 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
996 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
997 * not a trivial thing.
999 * The current offender is mono_thread_manage which cleanup threads from the outside.
1001 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
1002 jit_tls
= info
->jit_data
;
1003 info
->jit_data
= NULL
;
1005 mono_set_jit_tls (NULL
);
1007 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1008 if (mono_get_lmf ()) {
1009 mono_set_lmf (NULL
);
1010 mono_set_lmf_addr (NULL
);
1013 info
= mono_thread_info_lookup (tid
);
1015 jit_tls
= info
->jit_data
;
1016 info
->jit_data
= NULL
;
1018 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1022 free_jit_tls_data (jit_tls
);
1026 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
1028 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
1032 ji
->data
.target
= target
;
1038 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1040 static const char* const patch_info_str
[] = {
1041 #define PATCH_INFO(a,b) "" #a,
1042 #include "patch-info.h"
1047 mono_ji_type_to_string (MonoJumpInfoType type
)
1049 return patch_info_str
[type
];
1053 mono_print_ji (const MonoJumpInfo
*ji
)
1055 const char *type
= patch_info_str
[ji
->type
];
1057 case MONO_PATCH_INFO_RGCTX_FETCH
:
1058 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1059 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1061 printf ("[%s ", type
);
1062 mono_print_ji (entry
->data
);
1063 printf (" -> %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1066 case MONO_PATCH_INFO_METHOD
:
1067 case MONO_PATCH_INFO_METHODCONST
:
1068 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1069 char *s
= mono_method_get_full_name (ji
->data
.method
);
1070 printf ("[%s %s]", type
, s
);
1074 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1075 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji
->data
.jit_icall_id
)->name
);
1077 case MONO_PATCH_INFO_CLASS
:
1078 case MONO_PATCH_INFO_VTABLE
: {
1079 char *name
= mono_class_full_name (ji
->data
.klass
);
1080 printf ("[%s %s]", type
, name
);
1085 printf ("[%s]", type
);
1093 mono_ji_type_to_string (MonoJumpInfoType type
)
1099 mono_print_ji (const MonoJumpInfo
*ji
)
1106 * mono_patch_info_dup_mp:
1108 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1111 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1113 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1114 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1116 switch (patch_info
->type
) {
1117 case MONO_PATCH_INFO_RVA
:
1118 case MONO_PATCH_INFO_LDSTR
:
1119 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1120 case MONO_PATCH_INFO_LDTOKEN
:
1121 case MONO_PATCH_INFO_DECLSEC
:
1122 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1123 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1125 case MONO_PATCH_INFO_SWITCH
:
1126 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1127 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1128 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1129 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1131 case MONO_PATCH_INFO_RGCTX_FETCH
:
1132 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1133 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1134 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1135 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1137 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1138 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1139 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1141 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1142 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1143 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1145 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1146 MonoGSharedVtMethodInfo
*info
;
1147 MonoGSharedVtMethodInfo
*oinfo
;
1150 oinfo
= patch_info
->data
.gsharedvt_method
;
1151 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1152 res
->data
.gsharedvt_method
= info
;
1153 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1154 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1155 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1156 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1157 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1159 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1161 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1162 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1165 case MONO_PATCH_INFO_VIRT_METHOD
: {
1166 MonoJumpInfoVirtMethod
*info
;
1167 MonoJumpInfoVirtMethod
*oinfo
;
1169 oinfo
= patch_info
->data
.virt_method
;
1170 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1171 res
->data
.virt_method
= info
;
1172 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1183 mono_patch_info_hash (gconstpointer data
)
1185 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1186 const MonoJumpInfoType type
= ji
->type
;
1187 guint hash
= type
<< 8;
1190 case MONO_PATCH_INFO_RVA
:
1191 case MONO_PATCH_INFO_LDSTR
:
1192 case MONO_PATCH_INFO_LDTOKEN
:
1193 case MONO_PATCH_INFO_DECLSEC
:
1194 return hash
| ji
->data
.token
->token
;
1195 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1196 return hash
| ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1197 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: // Hash on the selector name
1198 case MONO_PATCH_INFO_LDSTR_LIT
:
1199 return g_str_hash (ji
->data
.name
);
1200 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1201 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1202 return hash
| g_str_hash (ji
->data
.name
);
1203 case MONO_PATCH_INFO_VTABLE
:
1204 case MONO_PATCH_INFO_CLASS
:
1205 case MONO_PATCH_INFO_IID
:
1206 case MONO_PATCH_INFO_ADJUSTED_IID
:
1207 case MONO_PATCH_INFO_METHODCONST
:
1208 case MONO_PATCH_INFO_METHOD
:
1209 case MONO_PATCH_INFO_METHOD_JUMP
:
1210 case MONO_PATCH_INFO_METHOD_FTNDESC
:
1211 case MONO_PATCH_INFO_IMAGE
:
1212 case MONO_PATCH_INFO_ICALL_ADDR
:
1213 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1214 case MONO_PATCH_INFO_FIELD
:
1215 case MONO_PATCH_INFO_SFLDA
:
1216 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1217 case MONO_PATCH_INFO_METHOD_RGCTX
:
1218 case MONO_PATCH_INFO_SIGNATURE
:
1219 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1220 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1221 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1222 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1223 return hash
| (gssize
)ji
->data
.target
;
1224 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1225 return hash
| (gssize
)ji
->data
.gsharedvt
->method
;
1226 case MONO_PATCH_INFO_RGCTX_FETCH
:
1227 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1228 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1229 hash
|= e
->in_mrgctx
| e
->info_type
| mono_patch_info_hash (e
->data
);
1231 return hash
| (gssize
)e
->d
.method
;
1233 return hash
| (gssize
)e
->d
.klass
;
1235 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1236 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1237 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1238 case MONO_PATCH_INFO_GC_NURSERY_START
:
1239 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1240 case MONO_PATCH_INFO_GOT_OFFSET
:
1241 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1242 case MONO_PATCH_INFO_AOT_MODULE
:
1243 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
:
1244 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
:
1246 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1247 return hash
| ji
->data
.uindex
;
1248 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1249 case MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR
:
1250 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1251 return hash
| ji
->data
.index
;
1252 case MONO_PATCH_INFO_SWITCH
:
1253 return hash
| ji
->data
.table
->table_size
;
1254 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1255 return hash
| (gssize
)ji
->data
.gsharedvt_method
->method
;
1256 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1257 return hash
| (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1258 case MONO_PATCH_INFO_VIRT_METHOD
: {
1259 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1261 return hash
| (gssize
)info
->klass
| (gssize
)info
->method
;
1263 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1264 return hash
| mono_signature_hash (ji
->data
.sig
);
1266 printf ("info type: %d\n", ji
->type
);
1267 mono_print_ji (ji
); printf ("\n");
1268 g_assert_not_reached ();
1274 * mono_patch_info_equal:
1276 * This might fail to recognize equivalent patches, i.e. floats, so its only
1277 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1281 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1283 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1284 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1286 MonoJumpInfoType
const ji1_type
= ji1
->type
;
1287 MonoJumpInfoType
const ji2_type
= ji2
->type
;
1289 if (ji1_type
!= ji2_type
)
1293 case MONO_PATCH_INFO_RVA
:
1294 case MONO_PATCH_INFO_LDSTR
:
1295 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1296 case MONO_PATCH_INFO_LDTOKEN
:
1297 case MONO_PATCH_INFO_DECLSEC
:
1298 return ji1
->data
.token
->image
== ji2
->data
.token
->image
&&
1299 ji1
->data
.token
->token
== ji2
->data
.token
->token
&&
1300 ji1
->data
.token
->has_context
== ji2
->data
.token
->has_context
&&
1301 ji1
->data
.token
->context
.class_inst
== ji2
->data
.token
->context
.class_inst
&&
1302 ji1
->data
.token
->context
.method_inst
== ji2
->data
.token
->context
.method_inst
;
1303 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1304 case MONO_PATCH_INFO_LDSTR_LIT
:
1305 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1306 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1307 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1308 case MONO_PATCH_INFO_RGCTX_FETCH
:
1309 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1310 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1311 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1313 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
);
1315 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1316 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1317 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1319 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1321 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1322 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1323 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1324 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
;
1325 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR
:
1326 return ji1
->data
.uindex
== ji2
->data
.uindex
;
1327 case MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR
:
1328 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1329 return ji1
->data
.index
== ji2
->data
.index
;
1330 case MONO_PATCH_INFO_JIT_ICALL_ID
:
1331 return ji1
->data
.jit_icall_id
== ji2
->data
.jit_icall_id
;
1332 case MONO_PATCH_INFO_VIRT_METHOD
:
1333 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1334 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1335 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
);
1336 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1340 return ji1
->data
.target
== ji2
->data
.target
;
1344 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1346 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1347 gconstpointer target
= NULL
;
1351 switch (patch_info
->type
) {
1352 case MONO_PATCH_INFO_BB
:
1354 * FIXME: This could be hit for methods without a prolog. Should use -1
1355 * but too much code depends on a 0 initial value.
1357 //g_assert (patch_info->data.bb->native_offset);
1358 target
= patch_info
->data
.bb
->native_offset
+ code
;
1360 case MONO_PATCH_INFO_ABS
:
1361 target
= patch_info
->data
.target
;
1363 case MONO_PATCH_INFO_LABEL
:
1364 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1366 case MONO_PATCH_INFO_IP
:
1369 case MONO_PATCH_INFO_METHOD_REL
:
1370 target
= code
+ patch_info
->data
.offset
;
1372 case MONO_PATCH_INFO_JIT_ICALL_ID
: {
1373 MonoJitICallInfo
* const mi
= mono_find_jit_icall_info (patch_info
->data
.jit_icall_id
);
1374 g_assertf (mi
, "unknown MONO_PATCH_INFO_JIT_ICALL_ID %d", (int)patch_info
->data
.jit_icall_id
);
1375 target
= mono_icall_get_wrapper (mi
);
1378 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1379 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
: {
1380 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1381 g_assertf (mi
, "unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info
->data
.name
);
1385 case MONO_PATCH_INFO_METHOD_JUMP
:
1386 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1387 if (!mono_error_ok (error
))
1390 case MONO_PATCH_INFO_METHOD
:
1391 if (patch_info
->data
.method
== method
) {
1394 /* get the trampoline to the method from the domain */
1395 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1396 if (!mono_error_ok (error
))
1400 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1402 * Return an ftndesc for either AOTed code, or for an interp entry.
1404 target
= mini_llvmonly_load_method_ftndesc (patch_info
->data
.method
, FALSE
, FALSE
, error
);
1405 return_val_if_nok (error
, NULL
);
1408 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1411 mono_domain_lock (domain
);
1412 if (!domain_jit_info (domain
)->method_code_hash
)
1413 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1414 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1416 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1417 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1419 mono_domain_unlock (domain
);
1423 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1424 target
= (gpointer
)&mono_polling_required
;
1426 case MONO_PATCH_INFO_SWITCH
: {
1427 gpointer
*jump_table
;
1429 if (method
&& method
->dynamic
) {
1430 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1432 if (mono_aot_only
) {
1433 jump_table
= (void **)mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1435 jump_table
= (void **)mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1439 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1440 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1443 target
= jump_table
;
1446 case MONO_PATCH_INFO_METHODCONST
:
1447 case MONO_PATCH_INFO_CLASS
:
1448 case MONO_PATCH_INFO_IMAGE
:
1449 case MONO_PATCH_INFO_FIELD
:
1450 case MONO_PATCH_INFO_SIGNATURE
:
1451 case MONO_PATCH_INFO_AOT_MODULE
:
1452 target
= patch_info
->data
.target
;
1454 case MONO_PATCH_INFO_IID
:
1455 mono_class_init_internal (patch_info
->data
.klass
);
1456 target
= GUINT_TO_POINTER (m_class_get_interface_id (patch_info
->data
.klass
));
1458 case MONO_PATCH_INFO_ADJUSTED_IID
:
1459 mono_class_init_internal (patch_info
->data
.klass
);
1460 target
= GUINT_TO_POINTER ((guint32
)(-((m_class_get_interface_id (patch_info
->data
.klass
) + 1) * TARGET_SIZEOF_VOID_P
)));
1462 case MONO_PATCH_INFO_VTABLE
:
1463 target
= mono_class_vtable_checked (domain
, patch_info
->data
.klass
, error
);
1464 mono_error_assert_ok (error
);
1466 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1467 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1469 if (del_tramp
->is_virtual
)
1470 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1472 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1475 case MONO_PATCH_INFO_SFLDA
: {
1476 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, patch_info
->data
.field
->parent
, error
);
1477 mono_error_assert_ok (error
);
1479 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1480 gpointer addr
= NULL
;
1482 mono_domain_lock (domain
);
1483 if (domain
->special_static_fields
)
1484 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1485 mono_domain_unlock (domain
);
1490 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (!method
|| mono_class_needs_cctor_run (vtable
->klass
, method
)))
1491 /* Done by the generated code */
1495 if (!mono_runtime_class_init_full (vtable
, error
)) {
1500 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1503 case MONO_PATCH_INFO_RVA
: {
1504 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1507 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1508 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1511 case MONO_PATCH_INFO_R4
:
1512 case MONO_PATCH_INFO_R8
:
1513 target
= patch_info
->data
.target
;
1515 case MONO_PATCH_INFO_EXC_NAME
:
1516 target
= patch_info
->data
.name
;
1518 case MONO_PATCH_INFO_LDSTR
:
1520 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1521 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1523 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1525 MonoClass
*handle_class
;
1527 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1528 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1529 if (!mono_error_ok (error
))
1531 mono_class_init_internal (handle_class
);
1532 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType
*)handle
));
1534 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1535 if (!mono_error_ok (error
))
1539 case MONO_PATCH_INFO_LDTOKEN
: {
1541 MonoClass
*handle_class
;
1543 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1544 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1545 mono_error_assert_msg_ok (error
, "Could not patch ldtoken");
1546 mono_class_init_internal (handle_class
);
1551 case MONO_PATCH_INFO_DECLSEC
:
1552 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1554 case MONO_PATCH_INFO_ICALL_ADDR
:
1555 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1556 /* run_cctors == 0 -> AOT */
1557 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1559 target
= mono_lookup_pinvoke_call_internal (patch_info
->data
.method
, error
);
1563 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
));
1569 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1571 if (!target
&& run_cctors
)
1572 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1575 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1576 target
= mono_thread_interruption_request_flag ();
1578 case MONO_PATCH_INFO_METHOD_RGCTX
:
1579 target
= mini_method_get_rgctx (patch_info
->data
.method
);
1581 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1582 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1584 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1587 case MONO_PATCH_INFO_BB_OVF
:
1588 case MONO_PATCH_INFO_EXC_OVF
:
1589 case MONO_PATCH_INFO_GOT_OFFSET
:
1590 case MONO_PATCH_INFO_NONE
:
1592 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1593 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1595 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1598 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1599 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1601 /* AOT, not needed */
1604 target
= mono_arch_get_seq_point_info (domain
, code
);
1607 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1608 int card_table_shift_bits
;
1609 gpointer card_table_mask
;
1611 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1614 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1618 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1621 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1625 mono_gc_get_nursery (&shift_bits
, &size
);
1627 target
= (gpointer
)(gssize
)shift_bits
;
1630 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1631 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1634 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1638 case MONO_PATCH_INFO_LDSTR_LIT
: {
1642 len
= strlen ((const char *)patch_info
->data
.target
);
1643 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1644 memcpy (s
, patch_info
->data
.target
, len
);
1649 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1650 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1652 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1653 target
= (gpointer
)mono_tls_get_tls_getter ((MonoTlsKey
)patch_info
->data
.index
);
1655 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1656 target
= (gpointer
)mono_tls_get_tls_setter ((MonoTlsKey
)patch_info
->data
.index
);
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_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2201 * We need to make sure this wrapper
2202 * is compiled because it might end up
2203 * in an (M)RGCTX if generic sharing
2204 * is enabled, and would be called
2205 * indirectly. If it were a
2206 * trampoline we'd try to patch that
2207 * indirect call, which is not
2210 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper_full (mi
, TRUE
));
2211 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2212 if (mono_llvm_only
) {
2213 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
2214 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2215 return_val_if_nok (error
, NULL
);
2216 return mono_get_addr_from_ftnptr (compiled_ptr
);
2219 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2220 if (mono_use_interpreter
)
2223 return mono_create_delegate_trampoline (target_domain
, method
->klass
);
2224 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
2225 nm
= mono_marshal_get_delegate_begin_invoke (method
);
2226 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2227 return_val_if_nok (error
, NULL
);
2228 return mono_get_addr_from_ftnptr (compiled_ptr
);
2229 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
2230 nm
= mono_marshal_get_delegate_end_invoke (method
);
2231 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2232 return_val_if_nok (error
, NULL
);
2233 return mono_get_addr_from_ftnptr (compiled_ptr
);
2237 full_name
= mono_method_full_name (method
, TRUE
);
2238 mono_error_set_invalid_program (error
, "Unrecognizable runtime implemented method '%s'", full_name
);
2243 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2244 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2246 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
|| info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_OUT
) {
2247 static MonoTrampInfo
*in_tinfo
, *out_tinfo
;
2248 MonoTrampInfo
*tinfo
;
2250 gboolean is_in
= info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
;
2252 if (is_in
&& in_tinfo
)
2253 return in_tinfo
->code
;
2254 else if (!is_in
&& out_tinfo
)
2255 return out_tinfo
->code
;
2258 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2260 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2262 if (mono_ee_features
.use_aot_trampolines
)
2263 mono_aot_get_trampoline_full (is_in
? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo
);
2265 mono_arch_get_gsharedvt_trampoline (&tinfo
, FALSE
);
2266 jinfo
= create_jit_info_for_trampoline (method
, tinfo
);
2267 mono_jit_info_table_add (mono_get_root_domain (), jinfo
);
2280 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
2282 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
2284 gpointer code
= NULL
, p
;
2286 MonoJitICallInfo
*callinfo
= NULL
;
2287 WrapperInfo
*winfo
= NULL
;
2288 gboolean use_interp
= FALSE
;
2292 if (mono_ee_features
.force_use_interpreter
&& !jit_only
)
2294 if (!use_interp
&& mono_interp_only_classes
) {
2295 for (GSList
*l
= mono_interp_only_classes
; l
; l
= l
->next
) {
2296 if (!strcmp (m_class_get_name (method
->klass
), (char*)l
->data
))
2301 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2307 /* Should be handled by the caller */
2308 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
2311 * ICALL wrappers are handled specially, since there is only one copy of them
2312 * shared by all appdomains.
2314 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2315 winfo
= mono_marshal_get_wrapper_info (method
);
2316 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
2317 callinfo
= mono_find_jit_icall_by_addr (winfo
->d
.icall
.func
);
2318 g_assert (callinfo
);
2320 /* Must be domain neutral since there is only one copy */
2321 opt
|= MONO_OPT_SHARED
;
2323 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2324 opt
&= ~MONO_OPT_SHARED
;
2327 if (opt
& MONO_OPT_SHARED
)
2328 target_domain
= mono_get_root_domain ();
2330 target_domain
= domain
;
2332 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2333 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2336 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
2337 MonoGenericContext
*ctx
= NULL
;
2338 if (method
->is_inflated
)
2339 ctx
= mono_method_get_context (method
);
2340 method
= info
->d
.synchronized_inner
.method
;
2342 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2343 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
2349 info
= lookup_method (target_domain
, method
);
2351 /* We can't use a domain specific method in another domain */
2352 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2355 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2356 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2360 if (!mono_runtime_class_init_full (vtable
, error
))
2362 return mono_create_ftnptr (target_domain
, info
->code_start
);
2366 #ifdef MONO_USE_AOT_COMPILER
2367 if (opt
& MONO_OPT_AOT
) {
2368 MonoDomain
*domain
= NULL
;
2370 if (mono_aot_mode
== MONO_AOT_MODE_INTERP
&& method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2371 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2373 if (info
->subtype
== WRAPPER_SUBTYPE_INTERP_IN
|| info
->subtype
== WRAPPER_SUBTYPE_INTERP_LMF
)
2374 /* AOT'd wrappers for interp must be owned by root domain */
2375 domain
= mono_get_root_domain ();
2379 domain
= mono_domain_get ();
2381 mono_class_init_internal (method
->klass
);
2383 code
= mono_aot_get_method (domain
, method
, error
);
2387 if (mono_gc_is_critical_method (method
)) {
2389 * The suspend code needs to be able to lookup these methods by ip in async context,
2390 * so preload their jit info.
2392 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, code
);
2397 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2398 * This is not a problem, since it will be initialized when the method is first
2399 * called by init_method ().
2401 if (!mono_llvm_only
&& !mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2402 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2403 mono_error_assert_ok (error
);
2404 if (!mono_runtime_class_init_full (vtable
, error
))
2414 code
= compile_special (method
, target_domain
, error
);
2416 if (!mono_error_ok (error
))
2420 if (!jit_only
&& !code
&& mono_aot_only
&& mono_use_interpreter
&& method
->wrapper_type
!= MONO_WRAPPER_OTHER
) {
2421 if (mono_llvm_only
) {
2422 /* Signal to the caller that AOTed code is not found */
2425 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2427 if (!mono_error_ok (error
))
2432 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2433 char *full_name
= mono_type_get_full_name (method
->klass
);
2434 mono_error_set_invalid_operation (error
, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name
);
2439 if (mono_aot_only
) {
2440 char *fullname
= mono_method_get_full_name (method
);
2441 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
);
2447 if (wait_or_register_method_to_compile (method
, target_domain
))
2449 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2450 unregister_method_for_compile (method
, target_domain
);
2452 if (!mono_error_ok (error
))
2455 if (!code
&& mono_llvm_only
) {
2456 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2457 g_assert_not_reached ();
2463 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2465 if ((method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
)) {
2469 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2471 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2476 p
= mono_create_ftnptr (target_domain
, code
);
2479 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2480 mono_loader_lock ();
2482 if (!callinfo
->wrapper
) {
2483 callinfo
->wrapper
= p
;
2484 mono_register_jit_icall_wrapper (callinfo
, p
);
2487 mono_loader_unlock ();
2494 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2498 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2503 * mono_jit_compile_method_jit_only:
2505 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2508 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2512 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2516 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2518 invalidated_delegate_trampoline (char *desc
)
2520 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2521 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2527 * mono_jit_free_method:
2529 * Free all memory allocated by the JIT for METHOD.
2532 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2534 MonoJitDynamicMethodInfo
*ji
;
2535 gboolean destroy
= TRUE
, removed
;
2536 GHashTableIter iter
;
2537 MonoJumpList
*jlist
;
2538 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2540 g_assert (method
->dynamic
);
2542 if (mono_use_interpreter
) {
2543 mono_domain_jit_code_hash_lock (domain
);
2544 /* InterpMethod is allocated in the domain mempool. We might haven't
2545 * allocated an InterpMethod for this instance yet */
2546 mono_internal_hash_table_remove (&info
->interp_code_hash
, method
);
2547 mono_domain_jit_code_hash_unlock (domain
);
2550 mono_domain_lock (domain
);
2551 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2552 mono_domain_unlock (domain
);
2557 mono_debug_remove_method (method
, domain
);
2558 mono_lldb_remove_method (domain
, method
, ji
);
2560 mono_domain_lock (domain
);
2561 g_hash_table_remove (info
->dynamic_code_hash
, method
);
2562 mono_domain_jit_code_hash_lock (domain
);
2563 removed
= mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2565 mono_domain_jit_code_hash_unlock (domain
);
2566 g_hash_table_remove (info
->jump_trampoline_hash
, method
);
2567 g_hash_table_remove (info
->seq_points
, method
);
2569 ji
->ji
->seq_points
= NULL
;
2571 /* requires the domain lock - took above */
2572 mono_conc_hashtable_remove (info
->runtime_invoke_hash
, method
);
2574 /* Remove jump targets in this method */
2575 g_hash_table_iter_init (&iter
, info
->jump_target_hash
);
2576 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2577 GSList
*tmp
, *remove
;
2580 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2581 guint8
*ip
= (guint8
*)tmp
->data
;
2583 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2584 remove
= g_slist_prepend (remove
, tmp
);
2586 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2587 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2589 g_slist_free (remove
);
2591 mono_domain_unlock (domain
);
2593 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2594 if (mini_debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2596 * Instead of freeing the code, change it to call an error routine
2597 * so people can fix their code.
2599 char *type
= mono_type_full_name (m_class_get_byval_arg (method
->klass
));
2600 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2603 mono_arch_invalidate_method (ji
->ji
, (gpointer
)invalidated_delegate_trampoline
, (gpointer
)type_and_method
);
2609 * This needs to be done before freeing code_mp, since the code address is the
2610 * key in the table, so if we free the code_mp first, another thread can grab the
2611 * same code address and replace our entry in the table.
2613 mono_jit_info_table_remove (domain
, ji
->ji
);
2616 mono_code_manager_destroy (ji
->code_mp
);
2621 mono_jit_search_all_backends_for_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**out_ji
)
2626 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
2628 ERROR_DECL (oerror
);
2630 /* Might be AOTed code */
2631 mono_class_init_internal (method
->klass
);
2632 code
= mono_aot_get_method (domain
, method
, oerror
);
2634 mono_error_assert_ok (oerror
);
2635 ji
= mono_jit_info_table_find (domain
, code
);
2637 if (!is_ok (oerror
))
2638 mono_error_cleanup (oerror
);
2640 /* Might be interpreted */
2641 ji
= mini_get_interp_callbacks ()->find_jit_info (domain
, method
);
2651 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2653 MonoDomain
*target_domain
;
2656 if (default_opt
& MONO_OPT_SHARED
)
2657 target_domain
= mono_get_root_domain ();
2659 target_domain
= domain
;
2661 info
= lookup_method (target_domain
, method
);
2663 /* We can't use a domain specific method in another domain */
2664 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2665 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2668 return info
->code_start
;
2677 static guint32 bisect_opt
= 0;
2678 static GHashTable
*bisect_methods_hash
= NULL
;
2681 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2684 char method_name
[2048];
2687 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2688 g_assert (bisect_methods_hash
);
2690 file
= fopen (method_list_filename
, "r");
2693 while (fgets (method_name
, sizeof (method_name
), file
)) {
2694 size_t len
= strlen (method_name
);
2696 g_assert (method_name
[len
- 1] == '\n');
2697 method_name
[len
- 1] = 0;
2698 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2700 g_assert (feof (file
));
2703 gboolean mono_do_single_method_regression
= FALSE
;
2704 guint32 mono_single_method_regression_opt
= 0;
2705 MonoMethod
*mono_current_single_method
;
2706 GSList
*mono_single_method_list
;
2707 GHashTable
*mono_single_method_hash
;
2710 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 opt
)
2714 if (bisect_methods_hash
) {
2715 char *name
= mono_method_full_name (method
, TRUE
);
2716 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2719 return opt
| bisect_opt
;
2721 if (!mono_do_single_method_regression
)
2723 if (!mono_current_single_method
) {
2724 if (!mono_single_method_hash
)
2725 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2726 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2727 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2728 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2732 if (method
== mono_current_single_method
)
2733 return mono_single_method_regression_opt
;
2738 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2740 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
2745 gpointer compiled_method
;
2746 gpointer runtime_invoke
;
2748 MonoDynCallInfo
*dyn_call_info
;
2749 MonoClass
*ret_box_class
;
2750 MonoMethodSignature
*sig
;
2751 gboolean gsharedvt_invoke
;
2752 gboolean use_interp
;
2753 gpointer
*wrapper_arg
;
2754 } RuntimeInvokeInfo
;
2756 static RuntimeInvokeInfo
*
2757 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, gboolean use_interp
, MonoError
*error
)
2760 RuntimeInvokeInfo
*info
;
2762 info
= g_new0 (RuntimeInvokeInfo
, 1);
2763 info
->compiled_method
= compiled_method
;
2764 info
->use_interp
= use_interp
;
2765 if (mono_llvm_only
&& method
->string_ctor
)
2766 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
2768 info
->sig
= mono_method_signature_internal (method
);
2770 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
2771 info
->vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2772 if (!mono_error_ok (error
))
2774 g_assert (info
->vtable
);
2776 MonoMethodSignature
*sig
= info
->sig
;
2780 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2781 * in full-aot mode, so we use a slower, but more generic wrapper if
2782 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2784 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2785 if (!mono_llvm_only
&& (mono_aot_only
|| mini_debug_options
.dyn_runtime_invoke
)) {
2786 gboolean supported
= TRUE
;
2789 if (method
->string_ctor
)
2790 sig
= mono_marshal_get_string_ctor_signature (method
);
2792 for (i
= 0; i
< sig
->param_count
; ++i
) {
2793 MonoType
*t
= sig
->params
[i
];
2795 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2799 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
2803 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
2804 if (mini_debug_options
.dyn_runtime_invoke
)
2805 g_assert (info
->dyn_call_info
);
2810 ret_type
= sig
->ret
;
2811 switch (ret_type
->type
) {
2812 case MONO_TYPE_VOID
:
2824 case MONO_TYPE_BOOLEAN
:
2825 case MONO_TYPE_CHAR
:
2828 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2831 info
->ret_box_class
= mono_defaults
.int_class
;
2833 case MONO_TYPE_STRING
:
2834 case MONO_TYPE_CLASS
:
2835 case MONO_TYPE_ARRAY
:
2836 case MONO_TYPE_SZARRAY
:
2837 case MONO_TYPE_OBJECT
:
2839 case MONO_TYPE_GENERICINST
:
2840 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
2841 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2843 case MONO_TYPE_VALUETYPE
:
2844 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2847 g_assert_not_reached ();
2851 if (info
->use_interp
)
2854 if (!info
->dyn_call_info
) {
2855 if (mono_llvm_only
) {
2856 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2857 g_assert_not_reached ();
2859 info
->gsharedvt_invoke
= TRUE
;
2860 if (!callee_gsharedvt
) {
2861 /* Invoke a gsharedvt out wrapper instead */
2862 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2863 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2865 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
2866 info
->wrapper_arg
[0] = mini_llvmonly_add_method_wrappers (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
2868 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2869 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2870 g_free (wrapper_sig
);
2872 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
2873 if (!mono_error_ok (error
)) {
2878 /* Gsharedvt methods can be invoked the same way */
2879 /* The out wrapper has the same signature as the compiled gsharedvt method */
2880 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2882 info
->wrapper_arg
= (gpointer
*)(mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
);
2884 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2885 g_free (wrapper_sig
);
2888 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
2889 if (!mono_error_ok (error
)) {
2899 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2901 MonoMethodSignature
*sig
= info
->sig
;
2902 MonoDomain
*domain
= mono_domain_get ();
2903 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2905 gpointer retval_ptr
;
2906 guint8 retval
[256];
2907 gpointer
*param_refs
;
2912 g_assert (info
->gsharedvt_invoke
);
2915 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2916 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2917 * signatures, so we only have to generate runtime invoke wrappers for these
2919 * This code also handles invocation of gsharedvt methods directly, no
2920 * out wrappers are used in that case.
2922 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2923 param_refs
= (gpointer
*)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2926 * The runtime invoke wrappers expects pointers to primitive types, so have to
2930 args
[pindex
++] = &obj
;
2931 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
2932 retval_ptr
= (gpointer
)&retval
;
2933 args
[pindex
++] = &retval_ptr
;
2935 for (i
= 0; i
< sig
->param_count
; ++i
) {
2936 MonoType
*t
= sig
->params
[i
];
2938 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
2939 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
2940 guint8
*nullable_buf
;
2943 size
= mono_class_value_size (klass
, NULL
);
2944 nullable_buf
= g_alloca (size
);
2945 g_assert (nullable_buf
);
2947 /* The argument pointed to by params [i] is either a boxed vtype or null */
2948 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
2949 params
[i
] = nullable_buf
;
2952 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
2953 param_refs
[i
] = params
[i
];
2954 params
[i
] = &(param_refs
[i
]);
2956 args
[pindex
++] = ¶ms
[i
];
2958 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2959 args
[pindex
++] = &info
->wrapper_arg
;
2961 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2963 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
2967 if (sig
->ret
->type
!= MONO_TYPE_VOID
&& info
->ret_box_class
)
2968 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2970 return *(MonoObject
**)retval
;
2974 * mono_jit_runtime_invoke:
2975 * \param method: the method to invoke
2976 * \param obj: this pointer
2977 * \param params: array of parameter values.
2978 * \param exc: Set to the exception raised in the managed method.
2979 * \param error: error or caught exception object
2980 * If \p exc is NULL, \p error is thrown instead.
2981 * If coop is enabled, \p exc argument is ignored -
2982 * all exceptions are caught and propagated through \p error
2985 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2987 MonoMethod
*invoke
, *callee
;
2988 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2989 MonoDomain
*domain
= mono_domain_get ();
2990 MonoJitDomainInfo
*domain_info
;
2991 RuntimeInvokeInfo
*info
, *info2
;
2992 MonoJitInfo
*ji
= NULL
;
2993 gboolean callee_gsharedvt
= FALSE
;
2995 if (mono_ee_features
.force_use_interpreter
)
2996 return mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3002 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
3003 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3007 domain_info
= domain_jit_info (domain
);
3009 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
3012 if (mono_security_core_clr_enabled ()) {
3014 * This might be redundant since mono_class_vtable () already does this,
3015 * but keep it just in case for moonlight.
3017 mono_class_setup_vtable (method
->klass
);
3018 if (mono_class_has_failure (method
->klass
)) {
3019 mono_error_set_for_class_failure (error
, method
->klass
);
3021 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
3026 gpointer compiled_method
;
3029 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3030 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3032 * Array Get/Set/Address methods. The JIT implements them using inline code
3033 * inside the runtime invoke wrappers, so no need to compile them.
3035 if (mono_aot_only
) {
3037 * Call a wrapper, since the runtime invoke wrapper was not generated.
3039 MonoMethod
*wrapper
;
3041 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
3042 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
3049 gboolean use_interp
= FALSE
;
3052 compiled_method
= mono_jit_compile_method_jit_only (callee
, error
);
3053 if (!compiled_method
) {
3054 g_assert (!mono_error_ok (error
));
3056 if (mono_use_interpreter
)
3061 if (mono_llvm_only
) {
3062 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
3063 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3064 if (callee_gsharedvt
)
3065 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
3068 if (!callee_gsharedvt
)
3069 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
3072 compiled_method
= NULL
;
3075 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, use_interp
, error
);
3076 if (!mono_error_ok (error
))
3079 mono_domain_lock (domain
);
3080 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
3081 mono_domain_unlock (domain
);
3089 * We need this here because mono_marshal_get_runtime_invoke can place
3090 * the helper method in System.Object and not the target class.
3092 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
3094 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3098 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3099 we always catch the exception and propagate it through the MonoError */
3100 gboolean catchExcInMonoError
=
3101 (exc
== NULL
) && mono_threads_are_safepoints_enabled ();
3102 MonoObject
*invoke_exc
= NULL
;
3103 if (catchExcInMonoError
)
3106 /* The wrappers expect this to be initialized to NULL */
3110 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3111 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
= NULL
;
3112 if (info
->dyn_call_info
) {
3113 if (!dyn_runtime_invoke
) {
3114 mono_domain_lock (domain
);
3116 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
3117 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method_jit_only (invoke
, error
);
3118 if (!dyn_runtime_invoke
&& mono_use_interpreter
) {
3119 info
->use_interp
= TRUE
;
3120 info
->dyn_call_info
= NULL
;
3121 } else if (!mono_error_ok (error
)) {
3122 mono_domain_unlock (domain
);
3125 mono_domain_unlock (domain
);
3128 if (info
->dyn_call_info
) {
3129 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
3131 int i
, pindex
, buf_size
;
3133 guint8 retval
[256];
3135 /* Convert the arguments to the format expected by start_dyn_call () */
3136 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
3139 args
[pindex
++] = &obj
;
3140 for (i
= 0; i
< sig
->param_count
; ++i
) {
3141 MonoType
*t
= sig
->params
[i
];
3144 args
[pindex
++] = ¶ms
[i
];
3145 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
3146 args
[pindex
++] = ¶ms
[i
];
3148 args
[pindex
++] = params
[i
];
3152 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3154 buf_size
= mono_arch_dyn_call_get_buf_size (info
->dyn_call_info
);
3155 buf
= g_alloca (buf_size
);
3156 memset (buf
, 0, buf_size
);
3159 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
);
3161 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
3162 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
3164 if (catchExcInMonoError
&& *exc
!= NULL
) {
3165 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3169 if (info
->ret_box_class
)
3170 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3172 return *(MonoObject
**)retval
;
3178 if (info
->use_interp
) {
3179 result
= mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3180 return_val_if_nok (error
, NULL
);
3181 } else if (mono_llvm_only
) {
3182 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
3186 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3188 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
3190 if (catchExcInMonoError
&& *exc
!= NULL
) {
3191 ((MonoException
*)(*exc
))->caught_in_unmanaged
= TRUE
;
3192 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3197 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
3199 MonoException
*exc
= NULL
;
3202 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3203 MONO_SIG_HANDLER_GET_CONTEXT
;
3205 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3207 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3209 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3210 if (mono_arch_is_int_overflow (ctx
, info
))
3212 * The spec says this throws ArithmeticException, but MS throws the derived
3213 * OverflowException.
3215 exc
= mono_get_exception_overflow ();
3217 exc
= mono_get_exception_divide_by_zero ();
3219 exc
= mono_get_exception_divide_by_zero ();
3223 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3226 mono_sigctx_to_monoctx (ctx
, &mctx
);
3227 mono_handle_native_crash ("SIGFPE", &mctx
, info
);
3228 if (mono_do_crash_chaining
) {
3229 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3234 mono_arch_handle_exception (ctx
, exc
);
3237 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3240 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler
)
3243 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3244 MONO_SIG_HANDLER_GET_CONTEXT
;
3246 if (mono_runtime_get_no_exec ())
3249 mono_sigctx_to_monoctx (ctx
, &mctx
);
3250 mono_handle_native_crash ("SIGILL", &mctx
, info
);
3251 if (mono_do_crash_chaining
) {
3252 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3256 g_assert_not_reached ();
3259 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3261 #define HAVE_SIG_INFO
3262 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3264 #ifdef MONO_SIG_HANDLER_DEBUG
3265 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3266 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3267 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3268 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3269 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3270 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3276 is_addr_implicit_null_check (void *addr
)
3278 /* implicit null checks are only expected to work on the first page. larger
3279 * offsets are expected to have an explicit null check */
3280 return addr
<= GUINT_TO_POINTER (mono_target_pagesize ());
3283 // This function is separate from mono_sigsegv_signal_handler
3284 // so debug_fault_addr can be seen in debugger stacks.
3285 #ifdef MONO_SIG_HANDLER_DEBUG
3287 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug
)
3289 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3292 MonoJitInfo
*ji
= NULL
;
3293 MonoDomain
*domain
= mono_domain_get ();
3294 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3295 gpointer fault_addr
= NULL
;
3298 #ifdef HAVE_SIG_INFO
3299 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3303 MONO_SIG_HANDLER_GET_CONTEXT
;
3305 mono_sigctx_to_monoctx (ctx
, &mctx
);
3307 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3308 if (mono_arch_is_single_step_event (info
, ctx
)) {
3309 mini_get_dbg_callbacks ()->single_step_event (ctx
);
3311 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3312 mini_get_dbg_callbacks ()->breakpoint_hit (ctx
);
3317 #if defined(HAVE_SIG_INFO)
3318 #if !defined(HOST_WIN32)
3319 fault_addr
= info
->si_addr
;
3320 if (mono_aot_is_pagefault (info
->si_addr
)) {
3321 mono_aot_handle_pagefault (info
->si_addr
);
3326 /* The thread might no be registered with the runtime */
3327 if (!mono_domain_get () || !jit_tls
) {
3328 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3330 mono_handle_native_crash ("SIGSEGV", &mctx
, info
);
3331 if (mono_do_crash_chaining
) {
3332 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3339 ji
= mono_jit_info_table_find_internal (domain
, mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3341 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3342 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3345 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3346 fault_addr
= info
->si_addr
;
3347 if (fault_addr
== NULL
) {
3348 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3351 if (jit_tls
&& jit_tls
->stack_size
&&
3352 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3354 * The hard-guard page has been hit: there is not much we can do anymore
3355 * Print a hopefully clear message and abort.
3357 mono_handle_hard_stack_ovf (jit_tls
, ji
, &mctx
, (guint8
*)info
->si_addr
);
3358 g_assert_not_reached ();
3360 /* The original handler might not like that it is executed on an altstack... */
3361 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3364 if (is_addr_implicit_null_check (info
->si_addr
)) {
3365 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3367 mono_handle_native_crash ("SIGSEGV", &mctx
, info
);
3373 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3376 mono_handle_native_crash ("SIGSEGV", &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3378 if (mono_do_crash_chaining
) {
3379 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3384 if (is_addr_implicit_null_check (fault_addr
)) {
3385 mono_arch_handle_exception (ctx
, NULL
);
3387 mono_handle_native_crash ("SIGSEGV", &mctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3392 #ifdef MONO_SIG_HANDLER_DEBUG
3394 // This function is separate from mono_sigsegv_signal_handler_debug
3395 // so debug_fault_addr can be seen in debugger stacks.
3396 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3399 gpointer
const debug_fault_addr
= (gpointer
)MONO_SIG_HANDLER_GET_INFO () ->ep
->ExceptionRecord
->ExceptionInformation
[1];
3400 #elif defined (HAVE_SIG_INFO)
3401 gpointer
const debug_fault_addr
= MONO_SIG_HANDLER_GET_INFO ()->si_addr
;
3403 #error No extra parameter is passed, not even 0, to avoid any confusion.
3405 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG
);
3408 #endif // MONO_SIG_HANDLER_DEBUG
3410 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3413 MONO_SIG_HANDLER_GET_CONTEXT
;
3415 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3417 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3419 mono_arch_handle_exception (ctx
, exc
);
3421 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3424 #ifndef DISABLE_REMOTING
3425 /* mono_jit_create_remoting_trampoline:
3426 * @method: pointer to the method info
3428 * Creates a trampoline which calls the remoting functions. This
3429 * is used in the vtable of transparent proxies.
3431 * Returns: a pointer to the newly created code
3434 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3437 guint8
*addr
= NULL
;
3441 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature_internal (method
)->generic_param_count
) {
3442 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3446 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3447 (mono_method_signature_internal (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3448 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
, error
);
3451 return_val_if_nok (error
, NULL
);
3452 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3453 return_val_if_nok (error
, NULL
);
3454 return mono_get_addr_from_ftnptr (addr
);
3458 static G_GNUC_UNUSED
void
3459 no_imt_trampoline (void)
3461 g_assert_not_reached ();
3464 static G_GNUC_UNUSED
void
3465 no_vcall_trampoline (void)
3467 g_assert_not_reached ();
3470 static gpointer
*vtable_trampolines
;
3471 static int vtable_trampolines_size
;
3474 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3476 int index
= slot_index
+ MONO_IMT_SIZE
;
3479 return mini_llvmonly_get_vtable_trampoline (vt
, slot_index
, index
);
3481 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3482 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3484 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3488 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3489 while (new_size
<= index
)
3491 new_table
= g_new0 (gpointer
, new_size
);
3493 if (vtable_trampolines
)
3494 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3495 g_free (vtable_trampolines
);
3496 mono_memory_barrier ();
3497 vtable_trampolines
= (void **)new_table
;
3498 vtable_trampolines_size
= new_size
;
3503 if (!vtable_trampolines
[index
])
3504 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3505 return vtable_trampolines
[index
];
3509 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3511 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3515 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3520 gpointer
*imt
= (gpointer
*)vt
;
3521 imt
-= MONO_IMT_SIZE
;
3523 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3527 create_delegate_method_ptr (MonoMethod
*method
, MonoError
*error
)
3531 if (method_is_dynamic (method
)) {
3532 /* Creating a trampoline would leak memory */
3533 func
= mono_compile_method_checked (method
, error
);
3534 return_val_if_nok (error
, NULL
);
3536 gpointer trampoline
= mono_runtime_create_jump_trampoline (mono_domain_get (), method
, TRUE
, error
);
3537 return_val_if_nok (error
, NULL
);
3538 func
= mono_create_ftnptr (mono_domain_get (), trampoline
);
3544 mini_init_delegate (MonoDelegateHandle delegate
, MonoError
*error
)
3546 MonoDelegate
*del
= MONO_HANDLE_RAW (delegate
);
3548 if (mono_use_interpreter
) {
3549 mini_get_interp_callbacks ()->init_delegate (del
, error
);
3550 return_if_nok (error
);
3553 if (mono_llvm_only
) {
3554 g_assert (del
->method
);
3555 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3556 del
->method_ptr
= mini_llvmonly_load_method_delegate (del
->method
, FALSE
, FALSE
, &del
->extra_arg
, error
);
3557 } else if (!del
->method_ptr
&& !del
->interp_method
) {
3558 del
->method_ptr
= create_delegate_method_ptr (del
->method
, error
);
3559 return_if_nok (error
);
3564 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3568 abs_offset
= offset
;
3570 abs_offset
= - abs_offset
;
3571 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ TARGET_SIZEOF_VOID_P
);
3575 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3577 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3580 static guint8
**cache
= NULL
;
3581 static int cache_size
= 0;
3586 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3589 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3590 is_interface
= mono_class_is_interface (method
->klass
);
3591 load_imt_reg
= is_virtual_generic
|| is_interface
;
3594 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
3596 offset
= MONO_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
3598 idx
= (offset
/ TARGET_SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3599 g_assert (idx
>= 0);
3601 /* Resize the cache to idx + 1 */
3602 if (cache_size
< idx
+ 1) {
3604 if (cache_size
< idx
+ 1) {
3606 int new_cache_size
= idx
+ 1;
3608 new_cache
= g_new0 (guint8
*, new_cache_size
);
3610 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3613 mono_memory_barrier ();
3615 cache_size
= new_cache_size
;
3623 /* FIXME Support more cases */
3624 if (mono_ee_features
.use_aot_trampolines
) {
3625 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3626 g_assert (cache
[idx
]);
3628 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3634 * mini_parse_debug_option:
3635 * @option: The option to parse.
3637 * Parses debug options for the mono runtime. The options are the same as for
3638 * the MONO_DEBUG environment variable.
3642 mini_parse_debug_option (const char *option
)
3644 // Empty string is ok as consequence of appending ",foo"
3645 // without first checking for empty.
3649 if (!strcmp (option
, "handle-sigint"))
3650 mini_debug_options
.handle_sigint
= TRUE
;
3651 else if (!strcmp (option
, "keep-delegates"))
3652 mini_debug_options
.keep_delegates
= TRUE
;
3653 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3654 mini_debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3655 else if (!strcmp (option
, "collect-pagefault-stats"))
3656 mini_debug_options
.collect_pagefault_stats
= TRUE
;
3657 else if (!strcmp (option
, "break-on-unverified"))
3658 mini_debug_options
.break_on_unverified
= TRUE
;
3659 else if (!strcmp (option
, "no-gdb-backtrace"))
3660 mini_debug_options
.no_gdb_backtrace
= TRUE
;
3661 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
3662 mini_debug_options
.suspend_on_native_crash
= TRUE
;
3663 else if (!strcmp (option
, "suspend-on-exception"))
3664 mini_debug_options
.suspend_on_exception
= TRUE
;
3665 else if (!strcmp (option
, "suspend-on-unhandled"))
3666 mini_debug_options
.suspend_on_unhandled
= TRUE
;
3667 else if (!strcmp (option
, "dont-free-domains"))
3668 mono_dont_free_domains
= TRUE
;
3669 else if (!strcmp (option
, "dyn-runtime-invoke"))
3670 mini_debug_options
.dyn_runtime_invoke
= TRUE
;
3671 else if (!strcmp (option
, "gdb"))
3672 mini_debug_options
.gdb
= TRUE
;
3673 else if (!strcmp (option
, "lldb"))
3674 mini_debug_options
.lldb
= TRUE
;
3675 else if (!strcmp (option
, "llvm-disable-self-init"))
3676 mini_debug_options
.llvm_disable_self_init
= TRUE
;
3677 else if (!strcmp (option
, "explicit-null-checks"))
3678 mini_debug_options
.explicit_null_checks
= TRUE
;
3679 else if (!strcmp (option
, "gen-seq-points"))
3680 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
3681 else if (!strcmp (option
, "gen-compact-seq-points"))
3682 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3683 else if (!strcmp (option
, "no-compact-seq-points"))
3684 mini_debug_options
.no_seq_points_compact_data
= TRUE
;
3685 else if (!strcmp (option
, "single-imm-size"))
3686 mini_debug_options
.single_imm_size
= TRUE
;
3687 else if (!strcmp (option
, "init-stacks"))
3688 mini_debug_options
.init_stacks
= TRUE
;
3689 else if (!strcmp (option
, "casts"))
3690 mini_debug_options
.better_cast_details
= TRUE
;
3691 else if (!strcmp (option
, "soft-breakpoints"))
3692 mini_debug_options
.soft_breakpoints
= TRUE
;
3693 else if (!strcmp (option
, "check-pinvoke-callconv"))
3694 mini_debug_options
.check_pinvoke_callconv
= TRUE
;
3695 else if (!strcmp (option
, "use-fallback-tls"))
3696 mini_debug_options
.use_fallback_tls
= TRUE
;
3697 else if (!strcmp (option
, "debug-domain-unload"))
3698 mono_enable_debug_domain_unload (TRUE
);
3699 else if (!strcmp (option
, "partial-sharing"))
3700 mono_set_partial_sharing_supported (TRUE
);
3701 else if (!strcmp (option
, "align-small-structs"))
3702 mono_align_small_structs
= TRUE
;
3703 else if (!strcmp (option
, "native-debugger-break"))
3704 mini_debug_options
.native_debugger_break
= TRUE
;
3705 else if (!strcmp (option
, "disable_omit_fp"))
3706 mini_debug_options
.disable_omit_fp
= TRUE
;
3707 // This is an internal testing feature.
3708 // Every tail. encountered is required to be optimized.
3710 else if (!strcmp (option
, "test-tailcall-require"))
3711 mini_debug_options
.test_tailcall_require
= TRUE
;
3712 else if (!strcmp (option
, "verbose-gdb"))
3713 mini_debug_options
.verbose_gdb
= TRUE
;
3714 else if (!strncmp (option
, "thread-dump-dir=", 16))
3715 mono_set_thread_dump_dir(g_strdup(option
+ 16));
3716 else if (!strncmp (option
, "aot-skip=", 9)) {
3717 mini_debug_options
.aot_skip_set
= TRUE
;
3718 mini_debug_options
.aot_skip
= atoi (option
+ 9);
3726 mini_parse_debug_options (void)
3728 char *options
= g_getenv ("MONO_DEBUG");
3729 gchar
**args
, **ptr
;
3734 args
= g_strsplit (options
, ",", -1);
3737 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
3738 const char *arg
= *ptr
;
3740 if (!mini_parse_debug_option (arg
)) {
3741 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
3742 // test-tailcall-require is also accepted but not documented.
3743 // empty string is also accepted and ignored as a consequence
3744 // of appending ",foo" without checking for empty.
3745 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'.\n");
3754 mini_get_debug_options (void)
3756 return &mini_debug_options
;
3760 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
3762 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3763 gpointer
* desc
= NULL
;
3765 if ((desc
= g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
3767 #if defined(__mono_ppc64__)
3768 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
3774 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
3782 mini_get_addr_from_ftnptr (gpointer descr
)
3784 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3785 return *(gpointer
*)descr
;
3792 register_jit_stats (void)
3794 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
3795 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
3796 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
3797 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
3798 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_interp
);
3799 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_method_to_ir
);
3800 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
);
3801 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
);
3802 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_long_opts
);
3803 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_typechecks
);
3804 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop
);
3805 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_emulate_ops
);
3806 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_optimize_branches
);
3807 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_global_vregs
);
3808 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce
);
3809 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_alias_analysis
);
3810 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_if_conversion
);
3811 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_bb_ordering
);
3812 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_compile_dominator_info
);
3813 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_compute_natural_loops
);
3814 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_insert_safepoints
);
3815 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_compute
);
3816 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_cprop
);
3817 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_deadce
);
3818 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_perform_abc_removal
);
3819 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_ssa_remove
);
3820 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop2
);
3821 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_handle_global_vregs2
);
3822 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce2
);
3823 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_optimize_branches2
);
3824 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_decompose_vtype_opts
);
3825 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
);
3826 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
);
3827 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_analyze_liveness
);
3828 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_linear_scan
);
3829 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_arch_allocate_vars
);
3830 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_spill_global_vars
);
3831 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_cprop3
);
3832 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_local_deadce3
);
3833 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_codegen
);
3834 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_create_jit_info
);
3835 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
);
3836 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
);
3837 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_jit_stats
.jit_time
);
3838 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.basic_blocks
);
3839 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.max_basic_blocks
);
3840 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocate_var
);
3841 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.code_reallocs
);
3842 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_code_size
);
3843 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_seq_points_size
);
3844 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlineable_methods
);
3845 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlined_methods
);
3846 mono_counters_register ("Regvars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.regvars
);
3847 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.locals_stack_size
);
3848 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_lookups
);
3849 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.cil_code_size
);
3850 mono_counters_register ("Native code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.native_code_size
);
3851 mono_counters_register ("Aliases found", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_found
);
3852 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_removed
);
3853 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.loads_eliminated
);
3854 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.stores_eliminated
);
3855 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.optimized_divisions
);
3858 static void runtime_invoke_info_free (gpointer value
);
3861 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
3863 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
3864 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
3866 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
3870 class_method_pair_hash (gconstpointer data
)
3872 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
3874 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
3878 mini_create_jit_domain_info (MonoDomain
*domain
)
3880 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
3882 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3883 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3884 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
3885 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3886 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
3887 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
3888 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3889 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
3890 mono_jit_code_hash_init (&info
->interp_code_hash
);
3892 domain
->runtime_info
= info
;
3896 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
3898 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
3899 g_slist_free ((GSList
*)jlist
->list
);
3903 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
3905 GSList
*list
= (GSList
*)value
;
3906 g_slist_free (list
);
3910 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
3912 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
3913 mono_code_manager_destroy (di
->code_mp
);
3918 runtime_invoke_info_free (gpointer value
)
3920 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
3922 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3923 if (info
->dyn_call_info
)
3924 mono_arch_dyn_call_free (info
->dyn_call_info
);
3930 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
3932 g_slist_free ((GSList
*)value
);
3936 mini_free_jit_domain_info (MonoDomain
*domain
)
3938 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3940 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
3941 g_hash_table_destroy (info
->jump_target_hash
);
3942 if (info
->jump_target_got_slot_hash
) {
3943 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
3944 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
3946 if (info
->dynamic_code_hash
) {
3947 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
3948 g_hash_table_destroy (info
->dynamic_code_hash
);
3950 g_hash_table_destroy (info
->method_code_hash
);
3951 g_hash_table_destroy (info
->jump_trampoline_hash
);
3952 g_hash_table_destroy (info
->jit_trampoline_hash
);
3953 g_hash_table_destroy (info
->delegate_trampoline_hash
);
3954 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
3955 g_hash_table_destroy (info
->mrgctx_hash
);
3956 g_hash_table_destroy (info
->method_rgctx_hash
);
3957 g_hash_table_destroy (info
->interp_method_pointer_hash
);
3958 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
3959 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
3960 g_hash_table_destroy (info
->seq_points
);
3961 g_hash_table_destroy (info
->arch_seq_points
);
3962 if (info
->agent_info
)
3963 mini_get_dbg_callbacks ()->free_domain_info (domain
);
3964 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
3965 if (info
->llvm_jit_callees
) {
3966 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
3967 g_hash_table_destroy (info
->llvm_jit_callees
);
3969 mono_internal_hash_table_destroy (&info
->interp_code_hash
);
3971 mono_llvm_free_domain_info (domain
);
3974 g_free (domain
->runtime_info
);
3975 domain
->runtime_info
= NULL
;
3978 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3981 code_manager_chunk_new (void *chunk
, int size
)
3983 mono_arch_code_chunk_new (chunk
, size
);
3987 code_manager_chunk_destroy (void *chunk
)
3989 mono_arch_code_chunk_destroy (chunk
);
3996 llvm_init_inner (void)
3998 if (!mono_llvm_load (NULL
))
4009 * Load and initialize LLVM support.
4010 * Return TRUE on success.
4013 mini_llvm_init (void)
4016 static gboolean llvm_inited
;
4017 static gboolean init_result
;
4019 mono_loader_lock_if_inited ();
4021 init_result
= llvm_init_inner ();
4024 mono_loader_unlock_if_inited ();
4032 mini_add_profiler_argument (const char *desc
)
4034 if (!profile_options
)
4035 profile_options
= g_ptr_array_new ();
4037 g_ptr_array_add (profile_options
, (gpointer
) desc
);
4041 static MonoEECallbacks interp_cbs
= {0};
4044 mini_install_interp_callbacks (MonoEECallbacks
*cbs
)
4046 memcpy (&interp_cbs
, cbs
, sizeof (MonoEECallbacks
));
4050 mini_get_interp_callbacks (void)
4055 static MonoDebuggerCallbacks dbg_cbs
;
4058 mini_install_dbg_callbacks (MonoDebuggerCallbacks
*cbs
)
4060 g_assert (cbs
->version
== MONO_DBG_CALLBACKS_VERSION
);
4061 memcpy (&dbg_cbs
, cbs
, sizeof (MonoDebuggerCallbacks
));
4064 MonoDebuggerCallbacks
*
4065 mini_get_dbg_callbacks (void)
4071 mono_ee_api_version (void)
4073 return MONO_EE_API_VERSION
;
4077 mono_interp_entry_from_trampoline (gpointer ccontext
, gpointer imethod
)
4079 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext
, imethod
);
4083 mono_interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
4085 mini_get_interp_callbacks ()->to_native_trampoline (addr
, ccontext
);
4089 mini_is_interpreter_enabled (void)
4091 return mono_use_interpreter
;
4095 mono_get_runtime_build_version (void);
4098 mini_init (const char *filename
, const char *runtime_version
)
4102 MonoRuntimeCallbacks callbacks
;
4103 MonoThreadInfoRuntimeCallbacks ticallbacks
;
4104 MonoCodeManagerCallbacks code_manager_callbacks
;
4106 MONO_VES_INIT_BEGIN ();
4108 CHECKED_MONO_INIT ();
4110 #if defined(__linux__)
4111 if (access ("/proc/self/maps", F_OK
) != 0) {
4112 g_print ("Mono requires /proc to be mounted.\n");
4117 mono_interp_stub_init ();
4118 #ifndef DISABLE_INTERPRETER
4119 if (mono_use_interpreter
)
4120 mono_ee_interp_init (mono_interp_opts_string
);
4123 mono_debugger_agent_stub_init ();
4125 mono_debugger_agent_init ();
4129 mini_get_dbg_callbacks ()->parse_options (sdb_options
);
4131 mono_os_mutex_init_recursive (&jit_mutex
);
4133 mono_cross_helpers_run ();
4135 mono_counters_init ();
4139 mini_jit_init_job_control ();
4141 /* Happens when using the embedding interface */
4142 if (!default_opt_set
)
4143 default_opt
= mono_parse_default_optimizations (NULL
);
4145 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4147 mono_set_generic_sharing_vt_supported (TRUE
);
4150 mono_set_generic_sharing_vt_supported (TRUE
);
4153 mono_tls_init_runtime_keys ();
4155 if (!global_codeman
)
4156 global_codeman
= mono_code_manager_new ();
4158 memset (&callbacks
, 0, sizeof (callbacks
));
4159 callbacks
.create_ftnptr
= mini_create_ftnptr
;
4160 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
4161 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
4162 callbacks
.get_runtime_build_version
= mono_get_runtime_build_version
;
4163 callbacks
.set_cast_details
= mono_set_cast_details
;
4164 callbacks
.debug_log
= mini_get_dbg_callbacks ()->debug_log
;
4165 callbacks
.debug_log_is_enabled
= mini_get_dbg_callbacks ()->debug_log_is_enabled
;
4166 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
4167 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
4168 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
4169 callbacks
.init_delegate
= mini_init_delegate
;
4170 #define JIT_INVOKE_WORKS
4171 #ifdef JIT_INVOKE_WORKS
4172 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
4174 #define JIT_TRAMPOLINES_WORK
4175 #ifdef JIT_TRAMPOLINES_WORK
4176 callbacks
.compile_method
= mono_jit_compile_method
;
4177 callbacks
.create_jump_trampoline
= mono_create_jump_trampoline
;
4178 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
4179 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
4180 callbacks
.free_method
= mono_jit_free_method
;
4181 #ifndef DISABLE_REMOTING
4182 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
4185 #ifndef DISABLE_REMOTING
4186 if (mono_use_interpreter
)
4187 callbacks
.interp_get_remoting_invoke
= mini_get_interp_callbacks ()->get_remoting_invoke
;
4189 callbacks
.is_interpreter_enabled
= mini_is_interpreter_enabled
;
4190 callbacks
.get_weak_field_indexes
= mono_aot_get_weak_field_indexes
;
4192 #ifndef DISABLE_CRASH_REPORTING
4193 callbacks
.install_state_summarizer
= mini_register_sigterm_handler
;
4196 mono_install_callbacks (&callbacks
);
4198 memset (&ticallbacks
, 0, sizeof (ticallbacks
));
4199 ticallbacks
.setup_async_callback
= mono_setup_async_callback
;
4200 ticallbacks
.thread_state_init_from_sigctx
= mono_thread_state_init_from_sigctx
;
4201 ticallbacks
.thread_state_init_from_handle
= mono_thread_state_init_from_handle
;
4202 ticallbacks
.thread_state_init
= mono_thread_state_init
;
4205 mono_w32handle_init ();
4208 mono_thread_info_runtime_init (&ticallbacks
);
4210 if (g_hasenv ("MONO_DEBUG")) {
4211 mini_parse_debug_options ();
4214 mono_code_manager_init ();
4216 memset (&code_manager_callbacks
, 0, sizeof (code_manager_callbacks
));
4217 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4218 code_manager_callbacks
.chunk_new
= code_manager_chunk_new
;
4219 code_manager_callbacks
.chunk_destroy
= code_manager_chunk_destroy
;
4221 mono_code_manager_install_callbacks (&code_manager_callbacks
);
4225 mono_arch_cpu_init ();
4229 mono_unwind_init ();
4231 if (mini_get_debug_options ()->lldb
|| g_hasenv ("MONO_LLDB")) {
4232 mono_lldb_init ("");
4233 mono_dont_free_domains
= TRUE
;
4236 #ifdef XDEBUG_ENABLED
4237 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
4239 mono_xdebug_init (mono_xdebug
);
4240 g_free (mono_xdebug
);
4241 /* So methods for multiple domains don't have the same address */
4242 mono_dont_free_domains
= TRUE
;
4243 mono_using_xdebug
= TRUE
;
4244 } else if (mini_get_debug_options ()->gdb
) {
4245 mono_xdebug_init ((char*)"gdb");
4246 mono_dont_free_domains
= TRUE
;
4247 mono_using_xdebug
= TRUE
;
4252 if (mono_use_llvm
) {
4253 if (!mono_llvm_load (NULL
)) {
4254 mono_use_llvm
= FALSE
;
4255 fprintf (stderr
, "Mono Warning: llvm support could not be loaded.\n");
4262 mono_trampolines_init ();
4264 if (default_opt
& MONO_OPT_AOT
)
4267 mini_get_dbg_callbacks ()->init ();
4270 mono_wasm_debugger_init ();
4273 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4274 mono_set_generic_sharing_supported (TRUE
);
4277 mono_thread_info_signals_init ();
4279 mono_init_native_crash_info ();
4281 #ifndef MONO_CROSS_COMPILE
4282 mono_runtime_install_handlers ();
4284 mono_threads_install_cleanup (mini_thread_cleanup
);
4286 #ifdef JIT_TRAMPOLINES_WORK
4287 mono_install_create_domain_hook (mini_create_jit_domain_info
);
4288 mono_install_free_domain_hook (mini_free_jit_domain_info
);
4290 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
4291 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
4292 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
4294 mono_profiler_state
.context_enable
= mini_profiler_context_enable
;
4295 mono_profiler_state
.context_get_this
= mini_profiler_context_get_this
;
4296 mono_profiler_state
.context_get_argument
= mini_profiler_context_get_argument
;
4297 mono_profiler_state
.context_get_local
= mini_profiler_context_get_local
;
4298 mono_profiler_state
.context_get_result
= mini_profiler_context_get_result
;
4299 mono_profiler_state
.context_free_buffer
= mini_profiler_context_free_buffer
;
4301 if (profile_options
)
4302 for (guint i
= 0; i
< profile_options
->len
; i
++)
4303 mono_profiler_load ((const char *) g_ptr_array_index (profile_options
, i
));
4305 mono_profiler_started ();
4307 if (mini_debug_options
.collect_pagefault_stats
)
4308 mono_aot_set_make_unreadable (TRUE
);
4310 if (runtime_version
)
4311 domain
= mono_init_version (filename
, runtime_version
);
4313 domain
= mono_init_from_assembly (filename
, filename
);
4315 if (mono_aot_only
) {
4316 /* This helps catch code allocation requests */
4317 mono_code_manager_set_read_only (domain
->code_mp
);
4318 mono_marshal_use_aot_wrappers (TRUE
);
4321 if (mono_llvm_only
) {
4322 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline
);
4323 mono_set_always_build_imt_trampolines (TRUE
);
4324 } else if (mono_aot_only
) {
4325 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
4327 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
4330 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4331 mono_arch_finish_init ();
4333 /* This must come after mono_init () in the aot-only case */
4334 mono_exceptions_init ();
4336 /* This should come after mono_init () too */
4339 mono_create_icall_signatures ();
4341 register_jit_stats ();
4343 #define JIT_CALLS_WORK
4344 #ifdef JIT_CALLS_WORK
4345 /* Needs to be called here since register_jit_icall depends on it */
4346 mono_marshal_init ();
4348 mono_arch_register_lowlevel_calls ();
4352 mono_generic_sharing_init ();
4355 #ifdef MONO_ARCH_SIMD_INTRINSICS
4356 mono_simd_intrinsics_init ();
4359 mono_tasklets_init ();
4361 register_trampolines (domain
);
4363 if (mono_compile_aot
)
4365 * Avoid running managed code when AOT compiling, since the platform
4366 * might only support aot-only execution.
4368 mono_runtime_set_no_exec (TRUE
);
4370 mono_mem_account_register_counters ();
4372 #define JIT_RUNTIME_WORKS
4373 #ifdef JIT_RUNTIME_WORKS
4374 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
4375 mono_runtime_init_checked (domain
, (MonoThreadStartCB
)mono_thread_start_cb
, mono_thread_attach_cb
, error
);
4376 mono_error_assert_ok (error
);
4377 mono_thread_attach (domain
);
4378 MONO_PROFILER_RAISE (thread_name
, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4381 if (mono_profiler_sampling_enabled ())
4382 mono_runtime_setup_stat_profiler ();
4384 MONO_PROFILER_RAISE (runtime_initialized
, ());
4386 MONO_VES_INIT_END ();
4392 register_icalls (void)
4394 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4395 ves_icall_get_frame_info
);
4396 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4397 ves_icall_get_trace
);
4398 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4399 mono_runtime_install_handlers
);
4400 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4401 mono_runtime_cleanup_handlers
);
4403 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4404 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4405 mini_get_dbg_callbacks ()->unhandled_exception
);
4409 * It's important that we pass `TRUE` as the last argument here, as
4410 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4411 * *did* emit a wrapper, we'd be looking at infinite recursion since
4412 * the wrapper would call the icall which would call the wrapper and
4415 register_icall (mono_profiler_raise_method_enter
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4416 register_icall (mono_profiler_raise_method_leave
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4417 register_icall (mono_profiler_raise_method_tail_call
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4418 register_icall (mono_profiler_raise_exception_clause
, mono_icall_sig_void_ptr_int_int_object
, TRUE
);
4420 register_icall (mono_trace_enter_method
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4421 register_icall (mono_trace_leave_method
, mono_icall_sig_void_ptr_ptr
, TRUE
);
4422 g_assert (mono_get_lmf_addr
== mono_tls_get_lmf_addr
);
4423 register_icall (mono_jit_set_domain
, mono_icall_sig_void_ptr
, TRUE
);
4424 register_icall (mono_domain_get
, mono_icall_sig_ptr
, TRUE
);
4426 register_icall (mono_llvm_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4427 register_icall (mono_llvm_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4428 register_icall (mono_llvm_resume_exception
, mono_icall_sig_void
, TRUE
);
4429 register_icall (mono_llvm_match_exception
, mono_icall_sig_int_ptr_int_int_ptr_object
, TRUE
);
4430 register_icall (mono_llvm_clear_exception
, NULL
, TRUE
);
4431 register_icall (mono_llvm_load_exception
, mono_icall_sig_object
, TRUE
);
4432 register_icall (mono_llvm_throw_corlib_exception
, mono_icall_sig_void_int
, TRUE
);
4433 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4434 register_icall (mono_llvm_set_unhandled_exception_handler
, NULL
, TRUE
);
4436 // FIXME: This is broken
4438 register_icall (mono_debug_personality
, mono_icall_sig_int_int_int_ptr_ptr_ptr
, TRUE
);
4442 if (!mono_llvm_only
) {
4443 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception
, mono_icall_sig_void_object
, TRUE
);
4444 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception
, mono_icall_sig_void_object
, TRUE
);
4445 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception
, mono_icall_sig_void_ptr
, TRUE
);
4447 register_icall (mono_thread_get_undeniable_exception
, mono_icall_sig_object
, FALSE
);
4448 register_icall (ves_icall_thread_finish_async_abort
, mono_icall_sig_void
, FALSE
);
4449 register_icall (mono_thread_interruption_checkpoint
, mono_icall_sig_object
, FALSE
);
4450 register_icall (mono_thread_force_interruption_checkpoint_noraise
, mono_icall_sig_object
, FALSE
);
4452 register_icall (mono_threads_state_poll
, mono_icall_sig_void
, FALSE
);
4454 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4455 register_opcode_emulation (OP_LMUL
, __emul_lmul
, mono_icall_sig_long_long_long
, mono_llmult
, FALSE
);
4456 register_opcode_emulation (OP_LDIV
, __emul_ldiv
, mono_icall_sig_long_long_long
, mono_lldiv
, FALSE
);
4457 register_opcode_emulation (OP_LDIV_UN
, __emul_ldiv_un
, mono_icall_sig_long_long_long
, mono_lldiv_un
, FALSE
);
4458 register_opcode_emulation (OP_LREM
, __emul_lrem
, mono_icall_sig_long_long_long
, mono_llrem
, FALSE
);
4459 register_opcode_emulation (OP_LREM_UN
, __emul_lrem_un
, mono_icall_sig_long_long_long
, mono_llrem_un
, FALSE
);
4461 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4462 register_opcode_emulation (OP_LMUL_OVF_UN
, __emul_lmul_ovf_un
, mono_icall_sig_long_long_long
, mono_llmult_ovf_un
, FALSE
);
4463 register_opcode_emulation (OP_LMUL_OVF
, __emul_lmul_ovf
, mono_icall_sig_long_long_long
, mono_llmult_ovf
, FALSE
);
4466 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4467 register_opcode_emulation (OP_LSHL
, __emul_lshl
, mono_icall_sig_long_long_int32
, mono_lshl
, TRUE
);
4468 register_opcode_emulation (OP_LSHR
, __emul_lshr
, mono_icall_sig_long_long_int32
, mono_lshr
, TRUE
);
4469 register_opcode_emulation (OP_LSHR_UN
, __emul_lshr_un
, mono_icall_sig_long_long_int32
, mono_lshr_un
, TRUE
);
4472 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4473 register_opcode_emulation (OP_IDIV
, __emul_op_idiv
, mono_icall_sig_int32_int32_int32
, mono_idiv
, FALSE
);
4474 register_opcode_emulation (OP_IDIV_UN
, __emul_op_idiv_un
, mono_icall_sig_int32_int32_int32
, mono_idiv_un
, FALSE
);
4475 register_opcode_emulation (OP_IREM
, __emul_op_irem
, mono_icall_sig_int32_int32_int32
, mono_irem
, FALSE
);
4476 register_opcode_emulation (OP_IREM_UN
, __emul_op_irem_un
, mono_icall_sig_int32_int32_int32
, mono_irem_un
, FALSE
);
4479 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4480 register_opcode_emulation (OP_IMUL
, __emul_op_imul
, mono_icall_sig_int32_int32_int32
, mono_imul
, TRUE
);
4483 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4484 register_opcode_emulation (OP_IMUL_OVF
, __emul_op_imul_ovf
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf
, FALSE
);
4485 register_opcode_emulation (OP_IMUL_OVF_UN
, __emul_op_imul_ovf_un
, mono_icall_sig_int32_int32_int32
, mono_imul_ovf_un
, FALSE
);
4488 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4489 register_opcode_emulation (OP_FDIV
, __emul_fdiv
, mono_icall_sig_double_double_double
, mono_fdiv
, FALSE
);
4492 register_opcode_emulation (OP_FCONV_TO_U8
, __emul_fconv_to_u8
, mono_icall_sig_ulong_double
, mono_fconv_u8_2
, FALSE
);
4493 register_opcode_emulation (OP_RCONV_TO_U8
, __emul_rconv_to_u8
, mono_icall_sig_ulong_float
, mono_rconv_u8
, FALSE
);
4494 register_opcode_emulation (OP_FCONV_TO_U4
, __emul_fconv_to_u4
, mono_icall_sig_uint32_double
, mono_fconv_u4_2
, FALSE
);
4495 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, __emul_fconv_to_ovf_i8
, mono_icall_sig_long_double
, mono_fconv_ovf_i8
, FALSE
);
4496 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, __emul_fconv_to_ovf_u8
, mono_icall_sig_ulong_double
, mono_fconv_ovf_u8
, FALSE
);
4497 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, __emul_rconv_to_ovf_i8
, mono_icall_sig_long_float
, mono_rconv_ovf_i8
, FALSE
);
4498 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, __emul_rconv_to_ovf_u8
, mono_icall_sig_ulong_float
, mono_rconv_ovf_u8
, FALSE
);
4501 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4502 register_opcode_emulation (OP_FCONV_TO_I8
, __emul_fconv_to_i8
, mono_icall_sig_long_double
, mono_fconv_i8
, FALSE
);
4503 register_opcode_emulation (OP_RCONV_TO_I8
, __emul_rconv_to_i8
, mono_icall_sig_long_float
, mono_rconv_i8
, FALSE
);
4506 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4507 register_opcode_emulation (OP_ICONV_TO_R_UN
, __emul_iconv_to_r_un
, mono_icall_sig_double_int32
, mono_conv_to_r8_un
, FALSE
);
4509 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4510 register_opcode_emulation (OP_LCONV_TO_R8
, __emul_lconv_to_r8
, mono_icall_sig_double_long
, mono_lconv_to_r8
, FALSE
);
4512 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4513 register_opcode_emulation (OP_LCONV_TO_R4
, __emul_lconv_to_r4
, mono_icall_sig_float_long
, mono_lconv_to_r4
, FALSE
);
4515 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4516 register_opcode_emulation (OP_LCONV_TO_R_UN
, __emul_lconv_to_r8_un
, mono_icall_sig_double_long
, mono_lconv_to_r8_un
, FALSE
);
4518 #ifdef MONO_ARCH_EMULATE_FREM
4519 register_opcode_emulation (OP_FREM
, __emul_frem
, mono_icall_sig_double_double_double
, mono_fmod
, FALSE
);
4520 register_opcode_emulation (OP_RREM
, __emul_rrem
, mono_icall_sig_float_float_float
, fmodf
, FALSE
);
4523 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4524 if (mono_arch_is_soft_float ()) {
4525 register_opcode_emulation (OP_FSUB
, __emul_fsub
, mono_icall_sig_double_double_double
, mono_fsub
, FALSE
);
4526 register_opcode_emulation (OP_FADD
, __emul_fadd
, mono_icall_sig_double_double_double
, mono_fadd
, FALSE
);
4527 register_opcode_emulation (OP_FMUL
, __emul_fmul
, mono_icall_sig_double_double_double
, mono_fmul
, FALSE
);
4528 register_opcode_emulation (OP_FNEG
, __emul_fneg
, mono_icall_sig_double_double
, mono_fneg
, FALSE
);
4529 register_opcode_emulation (OP_ICONV_TO_R8
, __emul_iconv_to_r8
, mono_icall_sig_double_int32
, mono_conv_to_r8
, FALSE
);
4530 register_opcode_emulation (OP_ICONV_TO_R4
, __emul_iconv_to_r4
, mono_icall_sig_double_int32
, mono_conv_to_r4
, FALSE
);
4531 register_opcode_emulation (OP_FCONV_TO_R4
, __emul_fconv_to_r4
, mono_icall_sig_double_double
, mono_fconv_r4
, FALSE
);
4532 register_opcode_emulation (OP_FCONV_TO_I1
, __emul_fconv_to_i1
, mono_icall_sig_int8_double
, mono_fconv_i1
, FALSE
);
4533 register_opcode_emulation (OP_FCONV_TO_I2
, __emul_fconv_to_i2
, mono_icall_sig_int16_double
, mono_fconv_i2
, FALSE
);
4534 register_opcode_emulation (OP_FCONV_TO_I4
, __emul_fconv_to_i4
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4535 register_opcode_emulation (OP_FCONV_TO_U1
, __emul_fconv_to_u1
, mono_icall_sig_uint8_double
, mono_fconv_u1
, FALSE
);
4536 register_opcode_emulation (OP_FCONV_TO_U2
, __emul_fconv_to_u2
, mono_icall_sig_uint16_double
, mono_fconv_u2
, FALSE
);
4538 #if TARGET_SIZEOF_VOID_P == 4
4539 register_opcode_emulation (OP_FCONV_TO_I
, __emul_fconv_to_i
, mono_icall_sig_int32_double
, mono_fconv_i4
, FALSE
);
4542 register_opcode_emulation (OP_FBEQ
, __emul_fcmp_eq
, mono_icall_sig_uint32_double_double
, mono_fcmp_eq
, FALSE
);
4543 register_opcode_emulation (OP_FBLT
, __emul_fcmp_lt
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt
, FALSE
);
4544 register_opcode_emulation (OP_FBGT
, __emul_fcmp_gt
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt
, FALSE
);
4545 register_opcode_emulation (OP_FBLE
, __emul_fcmp_le
, mono_icall_sig_uint32_double_double
, mono_fcmp_le
, FALSE
);
4546 register_opcode_emulation (OP_FBGE
, __emul_fcmp_ge
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge
, FALSE
);
4547 register_opcode_emulation (OP_FBNE_UN
, __emul_fcmp_ne_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ne_un
, FALSE
);
4548 register_opcode_emulation (OP_FBLT_UN
, __emul_fcmp_lt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_lt_un
, FALSE
);
4549 register_opcode_emulation (OP_FBGT_UN
, __emul_fcmp_gt_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_gt_un
, FALSE
);
4550 register_opcode_emulation (OP_FBLE_UN
, __emul_fcmp_le_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_le_un
, FALSE
);
4551 register_opcode_emulation (OP_FBGE_UN
, __emul_fcmp_ge_un
, mono_icall_sig_uint32_double_double
, mono_fcmp_ge_un
, FALSE
);
4553 register_opcode_emulation (OP_FCEQ
, __emul_fcmp_ceq
, mono_icall_sig_uint32_double_double
, mono_fceq
, FALSE
);
4554 register_opcode_emulation (OP_FCGT
, __emul_fcmp_cgt
, mono_icall_sig_uint32_double_double
, mono_fcgt
, FALSE
);
4555 register_opcode_emulation (OP_FCGT_UN
, __emul_fcmp_cgt_un
, mono_icall_sig_uint32_double_double
, mono_fcgt_un
, FALSE
);
4556 register_opcode_emulation (OP_FCLT
, __emul_fcmp_clt
, mono_icall_sig_uint32_double_double
, mono_fclt
, FALSE
);
4557 register_opcode_emulation (OP_FCLT_UN
, __emul_fcmp_clt_un
, mono_icall_sig_uint32_double_double
, mono_fclt_un
, FALSE
);
4559 register_icall (mono_fload_r4
, mono_icall_sig_double_ptr
, FALSE
);
4560 register_icall (mono_fstore_r4
, mono_icall_sig_void_double_ptr
, FALSE
);
4561 register_icall (mono_fload_r4_arg
, mono_icall_sig_uint32_double
, FALSE
);
4562 register_icall (mono_isfinite_double
, mono_icall_sig_int32_double
, FALSE
);
4565 register_icall (mono_ckfinite
, mono_icall_sig_double_double
, FALSE
);
4567 #ifdef COMPRESSED_INTERFACE_BITMAP
4568 register_icall (mono_class_interface_match
, mono_icall_sig_uint32_ptr_int32
, TRUE
);
4571 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4572 #if SIZEOF_REGISTER == 4
4573 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_uint32_double
, mono_fconv_u4
, TRUE
);
4575 register_opcode_emulation (OP_FCONV_TO_U
, __emul_fconv_to_u
, mono_icall_sig_ulong_double
, mono_fconv_u8
, TRUE
);
4578 /* other jit icalls */
4579 register_icall (ves_icall_mono_delegate_ctor
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4580 register_icall (ves_icall_mono_delegate_ctor_interp
, mono_icall_sig_void_object_object_ptr
, FALSE
);
4581 register_icall (mono_class_static_field_address
,
4582 mono_icall_sig_ptr_ptr_ptr
, FALSE
);
4583 register_icall (mono_ldtoken_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4584 register_icall (mono_ldtoken_wrapper_generic_shared
,
4585 mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4586 register_icall (mono_get_special_static_data
, mono_icall_sig_ptr_int
, FALSE
);
4587 register_icall (ves_icall_mono_ldstr
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4588 register_icall (mono_helper_stelem_ref_check
, mono_icall_sig_void_object_object
, FALSE
);
4589 register_icall (ves_icall_object_new
, mono_icall_sig_object_ptr_ptr
, FALSE
);
4590 register_icall (ves_icall_object_new_specific
, mono_icall_sig_object_ptr
, FALSE
);
4591 register_icall (ves_icall_array_new
, mono_icall_sig_object_ptr_ptr_int32
, FALSE
);
4592 register_icall (ves_icall_array_new_specific
, mono_icall_sig_object_ptr_int32
, FALSE
);
4593 register_icall (ves_icall_runtime_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4594 register_icall (mono_ldftn
, mono_icall_sig_ptr_ptr
, FALSE
);
4595 register_icall (mono_ldvirtfn
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4596 register_icall (mono_ldvirtfn_gshared
, mono_icall_sig_ptr_object_ptr
, FALSE
);
4597 register_icall (mono_helper_compile_generic_method
, mono_icall_sig_ptr_object_ptr_ptr
, FALSE
);
4598 register_icall (mono_helper_ldstr
, mono_icall_sig_object_ptr_int
, FALSE
);
4599 register_icall (mono_helper_ldstr_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4600 register_icall (mono_helper_newobj_mscorlib
, mono_icall_sig_object_int
, FALSE
);
4601 register_icall (mono_value_copy_internal
, mono_icall_sig_void_ptr_ptr_ptr
, FALSE
);
4602 register_icall (mono_object_castclass_unbox
, mono_icall_sig_object_object_ptr
, FALSE
);
4603 register_icall (mono_break
, NULL
, TRUE
);
4604 register_icall (mono_create_corlib_exception_0
, mono_icall_sig_object_int
, TRUE
);
4605 register_icall (mono_create_corlib_exception_1
, mono_icall_sig_object_int_object
, TRUE
);
4606 register_icall (mono_create_corlib_exception_2
, mono_icall_sig_object_int_object_object
, TRUE
);
4607 register_icall (mono_array_new_1
, mono_icall_sig_object_ptr_int
, FALSE
);
4608 register_icall (mono_array_new_2
, mono_icall_sig_object_ptr_int_int
, FALSE
);
4609 register_icall (mono_array_new_3
, mono_icall_sig_object_ptr_int_int_int
, FALSE
);
4610 register_icall (mono_array_new_4
, mono_icall_sig_object_ptr_int_int_int_int
, FALSE
);
4611 register_icall (mono_array_new_n_icall
, mono_icall_sig_object_ptr_int_ptr
, FALSE
);
4612 register_icall (mono_get_native_calli_wrapper
, mono_icall_sig_ptr_ptr_ptr_ptr
, FALSE
);
4613 register_icall (mono_resume_unwind
, mono_icall_sig_void_ptr
, TRUE
);
4614 register_icall (mono_gsharedvt_constrained_call
, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr
, FALSE
);
4615 register_icall (mono_gsharedvt_value_copy
, mono_icall_sig_void_ptr_ptr_ptr
, TRUE
);
4617 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4618 MonoRangeCopyFunction
const mono_gc_wbarrier_range_copy
= mono_gc_get_range_copy_func ();
4619 register_icall_no_wrapper (mono_gc_wbarrier_range_copy
, mono_icall_sig_void_ptr_ptr_int
);
4621 register_icall (mono_object_castclass_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4622 register_icall (mono_object_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
4623 register_icall (mono_generic_class_init
, mono_icall_sig_void_ptr
, FALSE
);
4624 register_icall (mono_fill_class_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4625 register_icall (mono_fill_method_rgctx
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4627 register_dyn_icall (mini_get_dbg_callbacks ()->user_break
, mono_debugger_agent_user_break
, mono_icall_sig_void
, FALSE
);
4629 register_icall (mini_llvm_init_method
, mono_icall_sig_void_ptr_int
, TRUE
);
4630 register_icall (mini_llvm_init_gshared_method_this
, mono_icall_sig_void_ptr_int_object
, TRUE
);
4631 register_icall (mini_llvm_init_gshared_method_mrgctx
, mono_icall_sig_void_ptr_int_ptr
, TRUE
);
4632 register_icall (mini_llvm_init_gshared_method_vtable
, mono_icall_sig_void_ptr_int_ptr
, TRUE
);
4634 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4635 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt
, mono_icall_sig_ptr_object_int_ptr_ptr
);
4636 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4637 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call
, mono_icall_sig_ptr_ptr_int_ptr
);
4638 /* This needs a wrapper so it can have a preserveall cconv */
4639 register_icall (mini_llvmonly_init_vtable_slot
, mono_icall_sig_ptr_ptr_int
, FALSE
);
4640 register_icall (mini_llvmonly_init_delegate
, mono_icall_sig_void_object
, TRUE
);
4641 register_icall (mini_llvmonly_init_delegate_virtual
, mono_icall_sig_void_object_object_ptr
, TRUE
);
4642 register_icall (mini_llvmonly_throw_nullref_exception
, mono_icall_sig_void
, TRUE
);
4644 register_icall (mono_get_assembly_object
, mono_icall_sig_object_ptr
, TRUE
);
4645 register_icall (mono_get_method_object
, mono_icall_sig_object_ptr
, TRUE
);
4646 register_icall (mono_throw_method_access
, mono_icall_sig_void_ptr_ptr
, FALSE
);
4647 register_icall_no_wrapper (mono_dummy_jit_icall
, mono_icall_sig_void
);
4649 register_icall_with_wrapper (mono_monitor_enter_internal
, mono_icall_sig_int32_obj
);
4650 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, mono_icall_sig_void_obj_ptr
);
4651 register_icall_no_wrapper (mono_monitor_enter_fast
, mono_icall_sig_int_obj
);
4652 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, mono_icall_sig_int_obj_ptr
);
4655 register_icall (pthread_getspecific
, mono_icall_sig_ptr_ptr
, TRUE
);
4657 /* Register tls icalls */
4658 register_icall_no_wrapper (mono_tls_get_thread
, mono_icall_sig_ptr
);
4659 register_icall_no_wrapper (mono_tls_get_jit_tls
, mono_icall_sig_ptr
);
4660 register_icall_no_wrapper (mono_tls_get_domain
, mono_icall_sig_ptr
);
4661 register_icall_no_wrapper (mono_tls_get_sgen_thread_info
, mono_icall_sig_ptr
);
4662 register_icall_no_wrapper (mono_tls_get_lmf_addr
, mono_icall_sig_ptr
);
4663 register_icall_no_wrapper (mono_tls_set_thread
, mono_icall_sig_void_ptr
);
4664 register_icall_no_wrapper (mono_tls_set_jit_tls
, mono_icall_sig_void_ptr
);
4665 register_icall_no_wrapper (mono_tls_set_domain
, mono_icall_sig_void_ptr
);
4666 register_icall_no_wrapper (mono_tls_set_sgen_thread_info
, mono_icall_sig_void_ptr
);
4667 register_icall_no_wrapper (mono_tls_set_lmf_addr
, mono_icall_sig_void_ptr
);
4669 register_icall_no_wrapper (mono_interp_entry_from_trampoline
, mono_icall_sig_void_ptr_ptr
);
4670 register_icall_no_wrapper (mono_interp_to_native_trampoline
, mono_icall_sig_void_ptr_ptr
);
4672 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4673 mono_arch_register_icall ();
4677 MonoJitStats mono_jit_stats
= {0};
4680 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4681 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4683 MONO_NO_SANITIZE_THREAD
4685 print_jit_stats (void)
4687 if (mono_jit_stats
.enabled
) {
4688 g_print ("Mono Jit statistics\n");
4689 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/ 100.0,
4690 mono_jit_stats
.max_ratio_method
);
4691 g_print ("Biggest method: %" G_GINT32_FORMAT
" (%s)\n", mono_jit_stats
.biggest_method_size
,
4692 mono_jit_stats
.biggest_method
);
4694 g_print ("Delegates created: %" G_GINT32_FORMAT
"\n", mono_stats
.delegate_creations
);
4695 g_print ("Initialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.initialized_class_count
);
4696 g_print ("Used classes: %" G_GINT32_FORMAT
"\n", mono_stats
.used_class_count
);
4697 g_print ("Generic vtables: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_vtable_count
);
4698 g_print ("Methods: %" G_GINT32_FORMAT
"\n", mono_stats
.method_count
);
4699 g_print ("Static data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_static_data_size
);
4700 g_print ("VTable data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_vtable_size
);
4701 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4703 g_print ("\nInitialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_class_count
);
4704 g_print ("Inflated types: %" G_GINT32_FORMAT
"\n", mono_stats
.inflated_type_count
);
4705 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4707 g_print ("Sharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_sharable_methods
);
4708 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_unsharable_methods
);
4709 g_print ("Shared generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_shared_methods
);
4710 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.gsharedvt_methods
);
4712 g_print ("IMT tables size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_tables_size
);
4713 g_print ("IMT number of tables: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_tables
);
4714 g_print ("IMT number of methods: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_methods
);
4715 g_print ("IMT used slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_used_slots
);
4716 g_print ("IMT colliding slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_slots_with_collisions
);
4717 g_print ("IMT max collisions: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_max_collisions_in_slot
);
4718 g_print ("IMT methods at max col: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_method_count_when_max_collisions
);
4719 g_print ("IMT trampolines size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_trampolines_size
);
4721 g_print ("JIT info table inserts: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_insert_count
);
4722 g_print ("JIT info table removes: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_remove_count
);
4723 g_print ("JIT info table lookups: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_lookup_count
);
4725 g_free (mono_jit_stats
.max_ratio_method
);
4726 mono_jit_stats
.max_ratio_method
= NULL
;
4727 g_free (mono_jit_stats
.biggest_method
);
4728 mono_jit_stats
.biggest_method
= NULL
;
4732 #ifdef DISABLE_CLEANUP
4734 mini_cleanup (MonoDomain
*domain
)
4739 mini_cleanup (MonoDomain
*domain
)
4741 if (mono_profiler_sampling_enabled ())
4742 mono_runtime_shutdown_stat_profiler ();
4744 MONO_PROFILER_RAISE (runtime_shutdown_begin
, ());
4747 mono_cominterop_release_all_rcws ();
4750 #ifndef MONO_CROSS_COMPILE
4752 * mono_domain_finalize () needs to be called early since it needs the
4753 * execution engine still fully working (it may invoke managed finalizers).
4755 mono_domain_finalize (domain
, 2000);
4758 /* This accesses metadata so needs to be called before runtime shutdown */
4761 #ifndef MONO_CROSS_COMPILE
4762 mono_runtime_cleanup (domain
);
4765 mono_threadpool_cleanup ();
4767 MONO_PROFILER_RAISE (runtime_shutdown_end
, ());
4769 mono_profiler_cleanup ();
4771 if (profile_options
)
4772 g_ptr_array_free (profile_options
, TRUE
);
4774 free_jit_tls_data (mono_tls_get_jit_tls ());
4776 mono_icall_cleanup ();
4778 mono_runtime_cleanup_handlers ();
4780 #ifndef MONO_CROSS_COMPILE
4781 mono_domain_free (domain
, TRUE
);
4786 mono_llvm_cleanup ();
4789 mono_aot_cleanup ();
4791 mono_trampolines_cleanup ();
4793 mono_unwind_cleanup ();
4795 mono_code_manager_destroy (global_codeman
);
4796 g_free (vtable_trampolines
);
4798 mini_jit_cleanup ();
4800 mono_tramp_info_cleanup ();
4802 mono_arch_cleanup ();
4804 mono_generic_sharing_cleanup ();
4806 mono_cleanup_native_crash_info ();
4810 mono_trace_cleanup ();
4812 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, stdout
);
4814 if (mono_inject_async_exc_method
)
4815 mono_method_desc_free (mono_inject_async_exc_method
);
4817 mono_tls_free_keys ();
4819 mono_os_mutex_destroy (&jit_mutex
);
4821 mono_code_manager_cleanup ();
4824 mono_w32handle_cleanup ();
4830 mono_set_defaults (int verbose_level
, guint32 opts
)
4832 mini_verbose
= verbose_level
;
4833 mono_set_optimizations (opts
);
4837 mono_disable_optimizations (guint32 opts
)
4839 default_opt
&= ~opts
;
4843 mono_set_optimizations (guint32 opts
)
4846 default_opt_set
= TRUE
;
4847 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4848 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
4851 mono_set_generic_sharing_vt_supported (TRUE
);
4856 mono_set_verbose_level (guint32 level
)
4858 mini_verbose
= level
;
4862 mono_get_runtime_build_version (void)
4864 return FULL_VERSION
;
4868 * mono_get_runtime_build_info:
4869 * The returned string is owned by the caller. The returned string
4870 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4871 * \returns the runtime version + build date in string format.
4874 mono_get_runtime_build_info (void)
4876 if (mono_build_date
)
4877 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
4879 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
4883 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
4885 GHashTable
*assemblies
= (GHashTable
*)user_data
;
4886 MonoImage
*image
= mono_assembly_get_image_internal (ass
);
4887 MonoMethod
*method
, *invoke
;
4890 if (g_hash_table_lookup (assemblies
, ass
))
4893 g_hash_table_insert (assemblies
, ass
, ass
);
4895 if (mini_verbose
> 0)
4896 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
4898 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
4901 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, error
);
4903 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4906 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
4908 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
4912 if (mini_verbose
> 1) {
4913 char * desc
= mono_method_full_name (method
, TRUE
);
4914 g_print ("Compiling %d %s\n", count
, desc
);
4917 mono_compile_method_checked (method
, error
);
4918 if (!is_ok (error
)) {
4919 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4922 if (strcmp (method
->name
, "Finalize") == 0) {
4923 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4924 mono_compile_method_checked (invoke
, error
);
4925 mono_error_assert_ok (error
);
4927 #ifndef DISABLE_REMOTING
4928 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature_internal (method
)->hasthis
) {
4929 invoke
= mono_marshal_get_remoting_invoke_with_check (method
, error
);
4930 mono_error_assert_ok (error
);
4931 mono_compile_method_checked (invoke
, error
);
4932 mono_error_assert_ok (error
);
4937 /* Load and precompile referenced assemblies as well */
4938 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
4939 mono_assembly_load_reference (image
, i
);
4940 if (image
->references
[i
])
4941 mono_precompile_assembly (image
->references
[i
], assemblies
);
4945 void mono_precompile_assemblies ()
4947 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
4949 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
4951 g_hash_table_destroy (assemblies
);
4956 * Have to export this for AOT.
4959 mono_personality (void)
4962 g_assert_not_reached ();
4965 static MonoBreakPolicy
4966 always_insert_breakpoint (MonoMethod
*method
)
4968 return MONO_BREAK_POLICY_ALWAYS
;
4971 static MonoBreakPolicyFunc break_policy_func
= always_insert_breakpoint
;
4974 * mono_set_break_policy:
4975 * \param policy_callback the new callback function
4977 * Allow embedders to decide whether to actually obey breakpoint instructions
4978 * (both break IL instructions and \c Debugger.Break method calls), for example
4979 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4980 * untrusted or semi-trusted code.
4982 * \p policy_callback will be called every time a break point instruction needs to
4983 * be inserted with the method argument being the method that calls \c Debugger.Break
4984 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4985 * if it wants the breakpoint to not be effective in the given method.
4986 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4989 mono_set_break_policy (MonoBreakPolicyFunc policy_callback
)
4991 if (policy_callback
)
4992 break_policy_func
= policy_callback
;
4994 break_policy_func
= always_insert_breakpoint
;
4998 mini_should_insert_breakpoint (MonoMethod
*method
)
5000 switch (break_policy_func (method
)) {
5001 case MONO_BREAK_POLICY_ALWAYS
:
5003 case MONO_BREAK_POLICY_NEVER
:
5005 case MONO_BREAK_POLICY_ON_DBG
:
5006 g_warning ("mdb no longer supported");
5009 g_warning ("Incorrect value returned from break policy callback");
5014 // Custom handlers currently only implemented by Windows.
5017 mono_runtime_install_custom_handlers (const char *handlers
)
5023 mono_runtime_install_custom_handlers_usage (void)
5026 "Custom Handlers:\n"
5027 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5028 " separated list of available handlers to install.\n"
5030 "No handlers supported on current platform.\n");
5032 #endif /* HOST_WIN32 */