3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/metadata/profiler-private.h>
43 #include <mono/metadata/mono-config.h>
44 #include <mono/metadata/environment.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/threads-types.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/runtime.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/utils/mono-math.h>
54 #include <mono/utils/mono-compiler.h>
55 #include <mono/utils/mono-counters.h>
56 #include <mono/utils/mono-error-internals.h>
57 #include <mono/utils/mono-logger-internals.h>
58 #include <mono/utils/mono-mmap.h>
59 #include <mono/utils/mono-path.h>
60 #include <mono/utils/mono-tls.h>
61 #include <mono/utils/mono-hwcap.h>
62 #include <mono/utils/dtrace.h>
63 #include <mono/utils/mono-signal-handler.h>
64 #include <mono/utils/mono-threads.h>
65 #include <mono/utils/mono-threads-coop.h>
66 #include <mono/utils/checked-build.h>
67 #include <mono/utils/mono-proclib.h>
68 #include <mono/metadata/w32handle.h>
69 #include <mono/metadata/threadpool.h>
72 #include "seq-points.h"
79 #include "jit-icalls.h"
82 #include "mini-llvm.h"
83 #include "debugger-agent.h"
86 #ifdef MONO_ARCH_LLVM_SUPPORTED
88 #include "mini-llvm-cpp.h"
93 #ifdef ENABLE_INTERPRETER
94 #include "interp/interp.h"
97 static guint32 default_opt
= 0;
98 static gboolean default_opt_set
= FALSE
;
100 gboolean mono_compile_aot
= FALSE
;
101 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
102 gboolean mono_aot_only
= FALSE
;
103 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
104 gboolean mono_llvm_only
= FALSE
;
105 MonoAotMode mono_aot_mode
= MONO_AOT_MODE_NONE
;
107 const char *mono_build_date
;
108 gboolean mono_do_signal_chaining
;
109 gboolean mono_do_crash_chaining
;
110 int mini_verbose
= 0;
113 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
114 * it can load AOT code compiled by LLVM.
116 gboolean mono_use_llvm
= FALSE
;
118 gboolean mono_use_interpreter
= FALSE
;
120 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
121 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
122 static mono_mutex_t jit_mutex
;
124 static MonoCodeManager
*global_codeman
;
126 MonoDebugOptions debug_options
;
128 #ifdef VALGRIND_JIT_REGISTER_MAP
129 int valgrind_register
;
131 GList
* mono_aot_paths
;
133 static GPtrArray
*profile_options
;
135 static GSList
*tramp_infos
;
137 static void register_icalls (void);
140 mono_running_on_valgrind (void)
143 if (RUNNING_ON_VALGRIND
){
144 #ifdef VALGRIND_JIT_REGISTER_MAP
145 valgrind_register
= TRUE
;
159 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
161 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
164 ud
->method
= (MonoMethod
*)key
;
168 G_GNUC_UNUSED
static char*
169 get_method_from_ip (void *ip
)
175 MonoDomain
*domain
= mono_domain_get ();
176 MonoDebugSourceLocation
*location
;
177 FindTrampUserData user_data
;
180 domain
= mono_get_root_domain ();
182 ji
= mono_jit_info_table_find_internal (domain
, (char *)ip
, TRUE
, TRUE
);
185 user_data
.method
= NULL
;
186 mono_domain_lock (domain
);
187 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
188 mono_domain_unlock (domain
);
189 if (user_data
.method
) {
190 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
191 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
197 } else if (ji
->is_trampoline
) {
198 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ((MonoTrampInfo
*)ji
->d
.tramp_info
)->name
);
202 method
= jinfo_get_method (ji
);
203 method_name
= mono_method_full_name (method
, TRUE
);
204 /* FIXME: unused ? */
205 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
207 res
= g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name
, method
, (int)((char*)ip
- (char*)ji
->code_start
), ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, domain
, domain
->friendly_name
);
209 mono_debug_free_source_location (location
);
210 g_free (method_name
);
217 * \param ip an instruction pointer address
219 * This method is used from a debugger to get the name of the
220 * method at address \p ip. This routine is typically invoked from
221 * a debugger like this:
223 * (gdb) print mono_pmip ($pc)
225 * \returns the name of the method at address \p ip.
230 return get_method_from_ip (ip
);
234 * mono_print_method_from_ip:
235 * \param ip an instruction pointer address
237 * This method is used from a debugger to get the name of the
238 * method at address \p ip.
240 * This prints the name of the method at address \p ip in the standard
241 * output. Unlike \c mono_pmip which returns a string, this routine
242 * prints the value on the standard output.
245 mono_print_method_from_ip (void *ip
)
249 MonoDebugSourceLocation
*source
;
250 MonoDomain
*domain
= mono_domain_get ();
251 MonoDomain
*target_domain
= mono_domain_get ();
252 FindTrampUserData user_data
;
253 MonoGenericSharingContext
*gsctx
;
254 const char *shared_type
;
257 domain
= mono_get_root_domain ();
258 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
259 if (ji
&& ji
->is_trampoline
) {
260 MonoTrampInfo
*tinfo
= (MonoTrampInfo
*)ji
->d
.tramp_info
;
262 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
268 user_data
.method
= NULL
;
269 mono_domain_lock (domain
);
270 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
271 mono_domain_unlock (domain
);
273 if (user_data
.method
) {
274 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
275 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
280 g_print ("No method at %p\n", ip
);
284 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
285 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
287 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
290 if (gsctx
->is_gsharedvt
)
291 shared_type
= "gsharedvt ";
293 shared_type
= "gshared ";
296 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
);
299 g_print ("%s:%d\n", source
->source_file
, source
->row
);
302 mono_debug_free_source_location (source
);
307 * mono_method_same_domain:
309 * Determine whenever two compiled methods are in the same domain, thus
310 * the address of the callee can be embedded in the caller.
312 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
316 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
320 * If the call was made from domain-neutral to domain-specific
321 * code, we can't patch the call site.
323 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
326 cmethod
= jinfo_get_method (caller
);
327 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
328 (strstr (cmethod
->name
, "InvokeInDomain"))) {
329 /* The InvokeInDomain methods change the current appdomain */
337 * mono_global_codeman_reserve:
339 * Allocate code memory from the global code manager.
341 void *mono_global_codeman_reserve (int size
)
346 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
348 if (!global_codeman
) {
349 /* This can happen during startup */
350 global_codeman
= mono_code_manager_new ();
351 return mono_code_manager_reserve (global_codeman
, size
);
355 ptr
= mono_code_manager_reserve (global_codeman
, size
);
361 /* The callback shouldn't take any locks */
363 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
366 mono_code_manager_foreach (global_codeman
, func
, user_data
);
371 * mono_create_unwind_op:
373 * Create an unwind op with the given parameters.
376 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
378 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
389 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
391 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
394 res
->has_context
= context
!= NULL
;
396 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
402 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
404 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
408 * mono_tramp_info_create:
410 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
411 * of JI, and UNWIND_OPS.
414 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
416 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
418 info
->name
= g_strdup ((char*)name
);
420 info
->code_size
= code_size
;
422 info
->unwind_ops
= unwind_ops
;
428 mono_tramp_info_free (MonoTrampInfo
*info
)
433 mono_free_unwind_info (info
->unwind_ops
);
434 if (info
->owns_uw_info
)
435 g_free (info
->uw_info
);
440 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
444 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
445 mono_jit_info_init (ji
, NULL
, info
->code
, info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
446 ji
->d
.tramp_info
= info
;
447 ji
->is_trampoline
= TRUE
;
449 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
451 mono_jit_info_table_add (domain
, ji
);
455 * mono_tramp_info_register:
457 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
462 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
470 domain
= mono_get_root_domain ();
473 copy
= mono_domain_alloc0 (domain
, sizeof (MonoTrampInfo
));
475 copy
= g_new0 (MonoTrampInfo
, 1);
477 copy
->code
= info
->code
;
478 copy
->code_size
= info
->code_size
;
479 copy
->name
= g_strdup (info
->name
);
481 if (info
->unwind_ops
) {
482 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
483 copy
->owns_uw_info
= TRUE
;
485 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
486 guint8
*temp
= copy
->uw_info
;
487 copy
->uw_info
= mono_domain_alloc (domain
, copy
->uw_info_len
);
488 memcpy (copy
->uw_info
, temp
, copy
->uw_info_len
);
492 /* Trampolines from aot have the unwind ops already encoded */
493 copy
->uw_info
= info
->uw_info
;
494 copy
->uw_info_len
= info
->uw_info_len
;
497 mono_save_trampoline_xdebug_info (info
);
498 mono_lldb_save_trampoline_info (info
);
500 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
502 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
506 /* If no root domain has been created yet, postpone the registration. */
508 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
510 } else if (copy
->uw_info
) {
511 /* Only register trampolines that have unwind infos */
512 register_trampoline_jit_info (domain
, copy
);
515 if (mono_jit_map_is_enabled ())
516 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
518 mono_tramp_info_free (info
);
522 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
524 mono_tramp_info_register_internal (info
, domain
, FALSE
);
528 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
530 mono_tramp_info_register_internal (info
, domain
, TRUE
);
534 mono_tramp_info_cleanup (void)
538 for (l
= tramp_infos
; l
; l
= l
->next
) {
539 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
541 mono_tramp_info_free (info
);
543 g_slist_free (tramp_infos
);
546 /* Register trampolines created before the root domain was created in the jit info tables */
548 register_trampolines (MonoDomain
*domain
)
552 for (l
= tramp_infos
; l
; l
= l
->next
) {
553 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
555 register_trampoline_jit_info (domain
, info
);
559 G_GNUC_UNUSED
static void
565 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
566 * Set a breakpoint in break_count () to break the last time <x> is done.
568 G_GNUC_UNUSED gboolean
569 mono_debug_count (void)
571 static int count
= 0, int_val
= 0;
572 static gboolean inited
, has_value
= FALSE
;
577 char *value
= g_getenv ("COUNT");
579 int_val
= atoi (value
);
589 if (count
== int_val
)
599 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
604 gconstpointer trampoline
;
605 MonoDomain
*domain
= mono_get_root_domain ();
606 gboolean check_exc
= TRUE
;
608 if (callinfo
->wrapper
)
609 return callinfo
->wrapper
;
611 if (callinfo
->trampoline
)
612 return callinfo
->trampoline
;
614 if (!strcmp (callinfo
->name
, "mono_thread_interruption_checkpoint"))
615 /* This icall is used to check for exceptions, so don't check in the wrapper */
618 name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
619 wrapper
= mono_marshal_get_icall_wrapper (callinfo
->sig
, name
, callinfo
->func
, check_exc
);
623 trampoline
= mono_compile_method_checked (wrapper
, &error
);
624 mono_error_assert_ok (&error
);
627 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, &error
);
628 mono_error_assert_ok (&error
);
629 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
633 if (!callinfo
->trampoline
) {
634 mono_register_jit_icall_wrapper (callinfo
, trampoline
);
635 callinfo
->trampoline
= trampoline
;
637 mono_loader_unlock ();
639 return callinfo
->trampoline
;
643 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
645 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
648 static MonoJitDynamicMethodInfo
*
649 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
651 MonoJitDynamicMethodInfo
*res
;
653 if (domain_jit_info (domain
)->dynamic_code_hash
)
654 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
661 register_opcode_emulation (int opcode
, const char *name
, const char *sigstr
, gpointer func
, const char *symbol
, gboolean no_throw
)
664 mini_register_opcode_emulation (opcode
, name
, sigstr
, func
, symbol
, no_throw
);
666 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
668 g_assert (!sig
->hasthis
);
669 g_assert (sig
->param_count
< 3);
671 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
672 mono_register_jit_icall_full (func
, name
, sig
, no_throw
, TRUE
, symbol
);
677 * For JIT icalls implemented in C.
678 * NAME should be the same as the name of the C function whose address is FUNC.
679 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
680 * can't throw exceptions.
683 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean avoid_wrapper
)
685 MonoMethodSignature
*sig
;
688 sig
= mono_create_icall_signature (sigstr
);
692 mono_register_jit_icall_full (func
, name
, sig
, avoid_wrapper
, FALSE
, avoid_wrapper
? name
: NULL
);
696 register_icall_no_wrapper (gpointer func
, const char *name
, const char *sigstr
)
698 MonoMethodSignature
*sig
;
701 sig
= mono_create_icall_signature (sigstr
);
705 mono_register_jit_icall_full (func
, name
, sig
, TRUE
, FALSE
, name
);
709 register_icall_with_wrapper (gpointer func
, const char *name
, const char *sigstr
)
711 MonoMethodSignature
*sig
;
714 sig
= mono_create_icall_signature (sigstr
);
718 mono_register_jit_icall_full (func
, name
, sig
, FALSE
, FALSE
, NULL
);
722 register_dyn_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
724 MonoMethodSignature
*sig
;
727 sig
= mono_create_icall_signature (sigstr
);
731 mono_register_jit_icall (func
, name
, sig
, save
);
737 MonoJitTlsData
*jit_tls
;
739 if ((jit_tls
= mono_tls_get_jit_tls ()))
742 * We do not assert here because this function can be called from
743 * mini-gc.c on a thread that has not executed any managed code, yet
744 * (the thread object allocation can trigger a collection).
750 mono_get_lmf_addr (void)
752 return (MonoLMF
**)mono_tls_get_lmf_addr ();
756 mono_set_lmf (MonoLMF
*lmf
)
758 (*mono_get_lmf_addr ()) = lmf
;
762 mono_get_jit_tls (void)
764 return (MonoJitTlsData
*)mono_tls_get_jit_tls ();
768 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
770 MonoThreadInfo
*info
;
772 mono_tls_set_jit_tls (jit_tls
);
774 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
775 info
= mono_thread_info_current ();
777 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
781 mono_set_lmf_addr (gpointer lmf_addr
)
783 MonoThreadInfo
*info
;
785 mono_tls_set_lmf_addr (lmf_addr
);
787 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
788 info
= mono_thread_info_current ();
790 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
796 * Push an MonoLMFExt frame on the LMF stack.
799 mono_push_lmf (MonoLMFExt
*ext
)
801 #ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
804 lmf_addr
= mono_get_lmf_addr ();
806 mono_arch_init_lmf_ext (ext
, *lmf_addr
);
808 mono_set_lmf ((MonoLMF
*)ext
);
817 * Pop the last frame from the LMF stack.
820 mono_pop_lmf (MonoLMF
*lmf
)
822 mono_set_lmf ((MonoLMF
*)(((gssize
)lmf
->previous_lmf
) & ~3));
826 * mono_jit_thread_attach:
828 * Called by Xamarin.Mac and other products. Attach thread to runtime if
829 * needed and switch to @domain.
831 * @return the original domain which needs to be restored, or NULL.
834 mono_jit_thread_attach (MonoDomain
*domain
)
839 g_assert (!mono_threads_is_blocking_transition_enabled ());
842 /* Happens when called from AOTed code which is only used in the root domain. */
843 domain
= mono_get_root_domain ();
848 attached
= mono_tls_get_jit_tls () != NULL
;
851 mono_thread_attach (domain
);
854 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
857 orig
= mono_domain_get ();
859 mono_domain_set (domain
, TRUE
);
861 return orig
!= domain
? orig
: NULL
;
865 * mono_jit_set_domain:
867 * Set domain to @domain if @domain is not null
870 mono_jit_set_domain (MonoDomain
*domain
)
872 g_assert (!mono_threads_is_blocking_transition_enabled ());
875 mono_domain_set (domain
, TRUE
);
880 * \param obj exception object
881 * Abort the thread, print exception information and stack trace
884 mono_thread_abort (MonoObject
*obj
)
886 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
888 /* handle_remove should be eventually called for this thread, too
891 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
892 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
)) {
895 mono_invoke_unhandled_exception_hook (obj
);
900 setup_jit_tls_data (gpointer stack_start
, gpointer abort_func
)
902 MonoJitTlsData
*jit_tls
;
905 jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
909 jit_tls
= g_new0 (MonoJitTlsData
, 1);
911 jit_tls
->abort_func
= (void (*)(MonoObject
*))abort_func
;
912 jit_tls
->end_of_stack
= stack_start
;
914 mono_set_jit_tls (jit_tls
);
916 lmf
= g_new0 (MonoLMF
, 1);
917 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
919 jit_tls
->first_lmf
= lmf
;
921 mono_set_lmf_addr (&jit_tls
->lmf
);
925 #ifdef MONO_ARCH_HAVE_TLS_INIT
926 mono_arch_tls_init ();
929 mono_setup_altstack (jit_tls
);
935 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
937 mono_arch_free_jit_tls_data (jit_tls
);
938 mono_free_altstack (jit_tls
);
940 g_free (jit_tls
->first_lmf
);
945 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
947 MonoThreadInfo
*thread
;
948 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
949 thread
= mono_thread_info_current_unchecked ();
951 thread
->jit_data
= jit_tls
;
953 mono_arch_cpu_init ();
956 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
959 mono_thread_abort_dummy (MonoObject
*obj
)
961 if (mono_thread_attach_aborted_cb
)
962 mono_thread_attach_aborted_cb (obj
);
964 mono_thread_abort (obj
);
968 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
970 MonoThreadInfo
*thread
;
971 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
972 thread
= mono_thread_info_current_unchecked ();
974 thread
->jit_data
= jit_tls
;
976 mono_arch_cpu_init ();
980 mini_thread_cleanup (MonoNativeThreadId tid
)
982 MonoJitTlsData
*jit_tls
= NULL
;
983 MonoThreadInfo
*info
;
985 info
= mono_thread_info_current_unchecked ();
987 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
988 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
989 * not a trivial thing.
991 * The current offender is mono_thread_manage which cleanup threads from the outside.
993 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
994 jit_tls
= (MonoJitTlsData
*)info
->jit_data
;
995 info
->jit_data
= NULL
;
997 mono_set_jit_tls (NULL
);
999 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1000 if (mono_get_lmf ()) {
1001 mono_set_lmf (NULL
);
1002 mono_set_lmf_addr (NULL
);
1005 info
= mono_thread_info_lookup (tid
);
1007 jit_tls
= (MonoJitTlsData
*)info
->jit_data
;
1008 info
->jit_data
= NULL
;
1010 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1014 free_jit_tls_data (jit_tls
);
1018 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
1020 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
1024 ji
->data
.target
= target
;
1030 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1032 static const char* const patch_info_str
[] = {
1033 #define PATCH_INFO(a,b) "" #a,
1034 #include "patch-info.h"
1039 mono_ji_type_to_string (MonoJumpInfoType type
)
1041 return patch_info_str
[type
];
1045 mono_print_ji (const MonoJumpInfo
*ji
)
1048 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1049 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1051 printf ("[RGCTX_FETCH ");
1052 mono_print_ji (entry
->data
);
1053 printf (" - %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1056 case MONO_PATCH_INFO_METHODCONST
: {
1057 char *s
= mono_method_full_name (ji
->data
.method
, TRUE
);
1058 printf ("[METHODCONST - %s]", s
);
1062 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
1063 printf ("[INTERNAL_METHOD - %s]", ji
->data
.name
);
1067 printf ("[%s]", patch_info_str
[ji
->type
]);
1075 mono_ji_type_to_string (MonoJumpInfoType type
)
1081 mono_print_ji (const MonoJumpInfo
*ji
)
1088 * mono_patch_info_dup_mp:
1090 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1093 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1095 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1096 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1098 switch (patch_info
->type
) {
1099 case MONO_PATCH_INFO_RVA
:
1100 case MONO_PATCH_INFO_LDSTR
:
1101 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1102 case MONO_PATCH_INFO_LDTOKEN
:
1103 case MONO_PATCH_INFO_DECLSEC
:
1104 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1105 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1107 case MONO_PATCH_INFO_SWITCH
:
1108 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1109 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1110 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1111 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1113 case MONO_PATCH_INFO_RGCTX_FETCH
:
1114 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1115 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1116 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1117 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1119 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1120 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1121 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1123 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1124 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1125 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1127 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1128 MonoGSharedVtMethodInfo
*info
;
1129 MonoGSharedVtMethodInfo
*oinfo
;
1132 oinfo
= patch_info
->data
.gsharedvt_method
;
1133 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1134 res
->data
.gsharedvt_method
= info
;
1135 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1136 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1137 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1138 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1139 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1141 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1143 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1144 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1147 case MONO_PATCH_INFO_VIRT_METHOD
: {
1148 MonoJumpInfoVirtMethod
*info
;
1149 MonoJumpInfoVirtMethod
*oinfo
;
1151 oinfo
= patch_info
->data
.virt_method
;
1152 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1153 res
->data
.virt_method
= info
;
1154 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1165 mono_patch_info_hash (gconstpointer data
)
1167 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1170 case MONO_PATCH_INFO_RVA
:
1171 case MONO_PATCH_INFO_LDSTR
:
1172 case MONO_PATCH_INFO_LDTOKEN
:
1173 case MONO_PATCH_INFO_DECLSEC
:
1174 return (ji
->type
<< 8) | ji
->data
.token
->token
;
1175 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1176 return (ji
->type
<< 8) | ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1177 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1178 return (ji
->type
<< 8) | g_str_hash (ji
->data
.name
);
1179 case MONO_PATCH_INFO_VTABLE
:
1180 case MONO_PATCH_INFO_CLASS
:
1181 case MONO_PATCH_INFO_IID
:
1182 case MONO_PATCH_INFO_ADJUSTED_IID
:
1183 case MONO_PATCH_INFO_METHODCONST
:
1184 case MONO_PATCH_INFO_METHOD
:
1185 case MONO_PATCH_INFO_METHOD_JUMP
:
1186 case MONO_PATCH_INFO_IMAGE
:
1187 case MONO_PATCH_INFO_ICALL_ADDR
:
1188 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1189 case MONO_PATCH_INFO_FIELD
:
1190 case MONO_PATCH_INFO_SFLDA
:
1191 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1192 case MONO_PATCH_INFO_METHOD_RGCTX
:
1193 case MONO_PATCH_INFO_SIGNATURE
:
1194 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1195 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1196 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1197 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1198 return (ji
->type
<< 8) | (gssize
)ji
->data
.target
;
1199 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1200 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt
->method
;
1201 case MONO_PATCH_INFO_RGCTX_FETCH
:
1202 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1203 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1205 return (ji
->type
<< 8) | (gssize
)e
->method
| (e
->in_mrgctx
) | e
->info_type
| mono_patch_info_hash (e
->data
);
1207 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1208 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1209 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1210 case MONO_PATCH_INFO_GC_NURSERY_START
:
1211 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1212 case MONO_PATCH_INFO_GOT_OFFSET
:
1213 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1214 case MONO_PATCH_INFO_AOT_MODULE
:
1215 case MONO_PATCH_INFO_JIT_THREAD_ATTACH
:
1216 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
:
1217 return (ji
->type
<< 8);
1218 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1219 return (ji
->type
<< 8) | (ji
->data
.index
);
1220 case MONO_PATCH_INFO_SWITCH
:
1221 return (ji
->type
<< 8) | ji
->data
.table
->table_size
;
1222 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1223 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt_method
->method
;
1224 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1225 /* Hash on the selector name */
1226 return g_str_hash (ji
->data
.target
);
1227 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1228 return (ji
->type
<< 8) | (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1229 case MONO_PATCH_INFO_LDSTR_LIT
:
1230 return g_str_hash (ji
->data
.target
);
1231 case MONO_PATCH_INFO_VIRT_METHOD
: {
1232 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1234 return (ji
->type
<< 8) | (gssize
)info
->klass
| (gssize
)info
->method
;
1236 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1237 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1238 return (ji
->type
<< 8) | g_str_hash (ji
->data
.target
);
1239 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1240 return (ji
->type
<< 8) | mono_signature_hash (ji
->data
.sig
);
1242 printf ("info type: %d\n", ji
->type
);
1243 mono_print_ji (ji
); printf ("\n");
1244 g_assert_not_reached ();
1250 * mono_patch_info_equal:
1252 * This might fail to recognize equivalent patches, i.e. floats, so its only
1253 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1257 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1259 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1260 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1262 if (ji1
->type
!= ji2
->type
)
1265 switch (ji1
->type
) {
1266 case MONO_PATCH_INFO_RVA
:
1267 case MONO_PATCH_INFO_LDSTR
:
1268 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1269 case MONO_PATCH_INFO_LDTOKEN
:
1270 case MONO_PATCH_INFO_DECLSEC
:
1271 if ((ji1
->data
.token
->image
!= ji2
->data
.token
->image
) ||
1272 (ji1
->data
.token
->token
!= ji2
->data
.token
->token
) ||
1273 (ji1
->data
.token
->has_context
!= ji2
->data
.token
->has_context
) ||
1274 (ji1
->data
.token
->context
.class_inst
!= ji2
->data
.token
->context
.class_inst
) ||
1275 (ji1
->data
.token
->context
.method_inst
!= ji2
->data
.token
->context
.method_inst
))
1278 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1279 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1280 case MONO_PATCH_INFO_RGCTX_FETCH
:
1281 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1282 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1283 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1285 return e1
->method
== e2
->method
&& e1
->in_mrgctx
== e2
->in_mrgctx
&& e1
->info_type
== e2
->info_type
&& mono_patch_info_equal (e1
->data
, e2
->data
);
1287 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1288 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1289 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1291 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1293 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1294 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1295 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1296 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
;
1297 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1298 return ji1
->data
.index
== ji2
->data
.index
;
1299 case MONO_PATCH_INFO_VIRT_METHOD
:
1300 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1301 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1302 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1303 if (ji1
->data
.target
== ji2
->data
.target
)
1305 return strcmp (ji1
->data
.target
, ji2
->data
.target
) == 0 ? 1 : 0;
1306 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1307 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
) ? 1 : 0;
1309 if (ji1
->data
.target
!= ji2
->data
.target
)
1318 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1320 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1321 gconstpointer target
= NULL
;
1325 switch (patch_info
->type
) {
1326 case MONO_PATCH_INFO_BB
:
1328 * FIXME: This could be hit for methods without a prolog. Should use -1
1329 * but too much code depends on a 0 initial value.
1331 //g_assert (patch_info->data.bb->native_offset);
1332 target
= patch_info
->data
.bb
->native_offset
+ code
;
1334 case MONO_PATCH_INFO_ABS
:
1335 target
= patch_info
->data
.target
;
1337 case MONO_PATCH_INFO_LABEL
:
1338 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1340 case MONO_PATCH_INFO_IP
:
1343 case MONO_PATCH_INFO_METHOD_REL
:
1344 target
= code
+ patch_info
->data
.offset
;
1346 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
1347 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1349 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info
->data
.name
);
1350 g_assert_not_reached ();
1352 target
= mono_icall_get_wrapper (mi
);
1355 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1356 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
: {
1357 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1359 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info
->data
.name
);
1360 g_assert_not_reached ();
1365 case MONO_PATCH_INFO_METHOD_JUMP
:
1366 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1367 if (!mono_error_ok (error
))
1370 case MONO_PATCH_INFO_METHOD
:
1371 if (patch_info
->data
.method
== method
) {
1374 /* get the trampoline to the method from the domain */
1375 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1376 if (!mono_error_ok (error
))
1380 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1383 mono_domain_lock (domain
);
1384 if (!domain_jit_info (domain
)->method_code_hash
)
1385 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1386 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1388 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1389 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1391 mono_domain_unlock (domain
);
1395 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1396 g_assert (mono_threads_is_coop_enabled ());
1397 target
= (gpointer
)&mono_polling_required
;
1399 case MONO_PATCH_INFO_SWITCH
: {
1400 gpointer
*jump_table
;
1402 if (method
&& method
->dynamic
) {
1403 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1405 if (mono_aot_only
) {
1406 jump_table
= (void **)mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1408 jump_table
= (void **)mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1412 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1413 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1416 target
= jump_table
;
1419 case MONO_PATCH_INFO_METHODCONST
:
1420 case MONO_PATCH_INFO_CLASS
:
1421 case MONO_PATCH_INFO_IMAGE
:
1422 case MONO_PATCH_INFO_FIELD
:
1423 case MONO_PATCH_INFO_SIGNATURE
:
1424 case MONO_PATCH_INFO_AOT_MODULE
:
1425 target
= patch_info
->data
.target
;
1427 case MONO_PATCH_INFO_IID
:
1428 mono_class_init (patch_info
->data
.klass
);
1429 target
= GUINT_TO_POINTER (patch_info
->data
.klass
->interface_id
);
1431 case MONO_PATCH_INFO_ADJUSTED_IID
:
1432 mono_class_init (patch_info
->data
.klass
);
1433 target
= GUINT_TO_POINTER ((guint32
)(-((patch_info
->data
.klass
->interface_id
+ 1) * SIZEOF_VOID_P
)));
1435 case MONO_PATCH_INFO_VTABLE
:
1436 target
= mono_class_vtable (domain
, patch_info
->data
.klass
);
1439 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1440 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1442 if (del_tramp
->is_virtual
)
1443 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1445 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1448 case MONO_PATCH_INFO_SFLDA
: {
1449 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.field
->parent
);
1451 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1452 gpointer addr
= NULL
;
1454 mono_domain_lock (domain
);
1455 if (domain
->special_static_fields
)
1456 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1457 mono_domain_unlock (domain
);
1463 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (method
&& mono_class_needs_cctor_run (vtable
->klass
, method
)))
1464 /* Done by the generated code */
1468 if (!mono_runtime_class_init_full (vtable
, error
)) {
1473 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1476 case MONO_PATCH_INFO_RVA
: {
1477 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1480 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1481 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1484 case MONO_PATCH_INFO_R4
:
1485 case MONO_PATCH_INFO_R8
:
1486 target
= patch_info
->data
.target
;
1488 case MONO_PATCH_INFO_EXC_NAME
:
1489 target
= patch_info
->data
.name
;
1491 case MONO_PATCH_INFO_LDSTR
:
1493 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1494 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1496 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1498 MonoClass
*handle_class
;
1500 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1501 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1502 if (!mono_error_ok (error
))
1504 mono_class_init (handle_class
);
1505 mono_class_init (mono_class_from_mono_type ((MonoType
*)handle
));
1507 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1508 if (!mono_error_ok (error
))
1512 case MONO_PATCH_INFO_LDTOKEN
: {
1514 MonoClass
*handle_class
;
1516 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1517 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1518 if (!mono_error_ok (error
))
1519 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error
));
1520 mono_class_init (handle_class
);
1525 case MONO_PATCH_INFO_DECLSEC
:
1526 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1528 case MONO_PATCH_INFO_ICALL_ADDR
:
1529 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1530 /* run_cctors == 0 -> AOT */
1531 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1532 const char *exc_class
;
1533 const char *exc_arg
;
1536 target
= mono_lookup_pinvoke_call (patch_info
->data
.method
, &exc_class
, &exc_arg
);
1538 if (mono_aot_only
) {
1539 mono_error_set_exception_instance (error
, mono_exception_from_name_msg (mono_defaults
.corlib
, "System", exc_class
, exc_arg
));
1542 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
));
1548 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1550 if (!target
&& run_cctors
)
1551 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1554 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1555 target
= mono_thread_interruption_request_flag ();
1557 case MONO_PATCH_INFO_METHOD_RGCTX
: {
1558 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.method
->klass
);
1561 target
= mono_method_lookup_rgctx (vtable
, mini_method_get_context (patch_info
->data
.method
)->method_inst
);
1564 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1565 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1567 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1570 case MONO_PATCH_INFO_BB_OVF
:
1571 case MONO_PATCH_INFO_EXC_OVF
:
1572 case MONO_PATCH_INFO_GOT_OFFSET
:
1573 case MONO_PATCH_INFO_NONE
:
1575 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1576 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1578 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1581 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1582 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1584 /* AOT, not needed */
1587 target
= mono_arch_get_seq_point_info (domain
, code
);
1590 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1591 int card_table_shift_bits
;
1592 gpointer card_table_mask
;
1594 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1597 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1601 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1604 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1608 mono_gc_get_nursery (&shift_bits
, &size
);
1610 target
= (gpointer
)(mgreg_t
)shift_bits
;
1613 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1614 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1617 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1621 case MONO_PATCH_INFO_LDSTR_LIT
: {
1625 len
= strlen ((const char *)patch_info
->data
.target
);
1626 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1627 memcpy (s
, patch_info
->data
.target
, len
);
1632 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1633 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1635 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1636 target
= mono_tls_get_tls_getter (patch_info
->data
.index
, FALSE
);
1638 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1639 target
= mono_tls_get_tls_setter (patch_info
->data
.index
, FALSE
);
1641 case MONO_PATCH_INFO_JIT_THREAD_ATTACH
: {
1642 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1647 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
: {
1648 target
= (gpointer
) &mono_profiler_state
.gc_allocation_count
;
1652 g_assert_not_reached ();
1655 return (gpointer
)target
;
1659 mini_init_gsctx (MonoDomain
*domain
, MonoMemPool
*mp
, MonoGenericContext
*context
, MonoGenericSharingContext
*gsctx
)
1661 MonoGenericInst
*inst
;
1664 memset (gsctx
, 0, sizeof (MonoGenericSharingContext
));
1666 if (context
&& context
->class_inst
) {
1667 inst
= context
->class_inst
;
1668 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1669 MonoType
*type
= inst
->type_argv
[i
];
1671 if (mini_is_gsharedvt_gparam (type
))
1672 gsctx
->is_gsharedvt
= TRUE
;
1675 if (context
&& context
->method_inst
) {
1676 inst
= context
->method_inst
;
1678 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1679 MonoType
*type
= inst
->type_argv
[i
];
1681 if (mini_is_gsharedvt_gparam (type
))
1682 gsctx
->is_gsharedvt
= TRUE
;
1688 * LOCKING: Acquires the jit code hash lock.
1691 mini_lookup_method (MonoDomain
*domain
, MonoMethod
*method
, MonoMethod
*shared
)
1694 static gboolean inited
= FALSE
;
1695 static int lookups
= 0;
1696 static int failed_lookups
= 0;
1698 mono_domain_jit_code_hash_lock (domain
);
1699 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
1700 if (!ji
&& shared
) {
1701 /* Try generic sharing */
1702 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, shared
);
1703 if (ji
&& !ji
->has_generic_jit_info
)
1706 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &lookups
);
1707 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &failed_lookups
);
1715 mono_domain_jit_code_hash_unlock (domain
);
1721 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
1726 ji
= mini_lookup_method (domain
, method
, NULL
);
1729 if (!mono_method_is_generic_sharable (method
, FALSE
))
1731 shared
= mini_get_shared_method (method
);
1732 ji
= mini_lookup_method (domain
, method
, shared
);
1739 mono_get_jit_info_from_method (MonoDomain
*domain
, MonoMethod
*method
)
1741 return lookup_method (domain
, method
);
1745 mini_get_class (MonoMethod
*method
, guint32 token
, MonoGenericContext
*context
)
1750 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1751 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
1753 klass
= mono_class_inflate_generic_class_checked (klass
, context
, &error
);
1754 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
1757 klass
= mono_class_get_and_inflate_typespec_checked (method
->klass
->image
, token
, context
, &error
);
1758 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
1761 mono_class_init (klass
);
1766 static FILE* perf_map_file
;
1769 mono_enable_jit_map (void)
1771 if (!perf_map_file
) {
1773 g_snprintf (name
, sizeof (name
), "/tmp/perf-%d.map", getpid ());
1775 perf_map_file
= fopen (name
, "w");
1780 mono_emit_jit_tramp (void *start
, int size
, const char *desc
)
1783 fprintf (perf_map_file
, "%llx %x %s\n", (long long unsigned int)(gsize
)start
, size
, desc
);
1787 mono_emit_jit_map (MonoJitInfo
*jinfo
)
1789 if (perf_map_file
) {
1790 char *name
= mono_method_full_name (jinfo_get_method (jinfo
), TRUE
);
1791 mono_emit_jit_tramp (jinfo
->code_start
, jinfo
->code_size
, name
);
1797 mono_jit_map_is_enabled (void)
1799 return perf_map_file
!= NULL
;
1805 no_gsharedvt_in_wrapper (void)
1807 g_assert_not_reached ();
1813 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.
1814 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1815 Dependency management in this case is too complex to justify implementing it.
1817 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1820 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1821 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1822 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1823 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1828 int compilation_count
; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1829 int ref_count
; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1830 int threads_waiting
; /* Number of threads waiting on this job */
1831 gboolean has_cond
; /* True if @cond was initialized */
1832 gboolean done
; /* True if the method finished JIT'ing */
1833 MonoCoopCond cond
; /* Cond sleeping threads wait one */
1834 } JitCompilationEntry
;
1837 GPtrArray
*in_flight_methods
; //JitCompilationEntry*
1839 } JitCompilationData
;
1841 static JitCompilationData compilation_data
;
1842 static int jit_methods_waited
, jit_methods_multiple
, jit_methods_overload
, jit_spurious_wakeups
;
1845 mini_jit_init_job_control (void)
1847 mono_coop_mutex_init (&compilation_data
.lock
);
1848 compilation_data
.in_flight_methods
= g_ptr_array_new ();
1852 lock_compilation_data (void)
1854 mono_coop_mutex_lock (&compilation_data
.lock
);
1858 unlock_compilation_data (void)
1860 mono_coop_mutex_unlock (&compilation_data
.lock
);
1863 static JitCompilationEntry
*
1864 find_method (MonoMethod
*method
, MonoDomain
*domain
)
1867 for (i
= 0; i
< compilation_data
.in_flight_methods
->len
; ++i
){
1868 JitCompilationEntry
*e
= compilation_data
.in_flight_methods
->pdata
[i
];
1869 if (e
->method
== method
&& e
->domain
== domain
)
1877 add_current_thread (MonoJitTlsData
*jit_tls
)
1879 ++jit_tls
->active_jit_methods
;
1883 unref_jit_entry (JitCompilationEntry
*entry
)
1886 if (entry
->ref_count
)
1888 if (entry
->has_cond
)
1889 mono_coop_cond_destroy (&entry
->cond
);
1894 * Returns true if this method waited successfully for another thread to JIT it
1897 wait_or_register_method_to_compile (MonoMethod
*method
, MonoDomain
*domain
)
1899 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1900 JitCompilationEntry
*entry
;
1902 static gboolean inited
;
1904 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_waited
);
1905 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_multiple
);
1906 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_overload
);
1907 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_spurious_wakeups
);
1911 lock_compilation_data ();
1913 if (!(entry
= find_method (method
, domain
))) {
1914 entry
= g_new0 (JitCompilationEntry
, 1);
1915 entry
->method
= method
;
1916 entry
->domain
= domain
;
1917 entry
->compilation_count
= entry
->ref_count
= 1;
1918 g_ptr_array_add (compilation_data
.in_flight_methods
, entry
);
1919 g_assert (find_method (method
, domain
) == entry
);
1920 add_current_thread (jit_tls
);
1922 unlock_compilation_data ();
1924 } else if (jit_tls
->active_jit_methods
> 0) {
1925 //We can't suspend the current thread if it's already JITing a method.
1926 //Dependency management is too compilated and we want to get rid of this anyways.
1927 ++entry
->compilation_count
;
1928 ++jit_methods_multiple
;
1929 ++jit_tls
->active_jit_methods
;
1931 unlock_compilation_data ();
1934 ++jit_methods_waited
;
1937 if (!entry
->has_cond
) {
1938 mono_coop_cond_init (&entry
->cond
);
1939 entry
->has_cond
= TRUE
;
1943 ++entry
->threads_waiting
;
1945 g_assert (entry
->has_cond
);
1946 mono_coop_cond_wait (&entry
->cond
, &compilation_data
.lock
);
1947 --entry
->threads_waiting
;
1950 unref_jit_entry (entry
);
1951 unlock_compilation_data ();
1954 ++jit_spurious_wakeups
;
1961 unregister_method_for_compile (MonoMethod
*method
, MonoDomain
*target_domain
)
1963 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1965 lock_compilation_data ();
1967 g_assert (jit_tls
->active_jit_methods
> 0);
1968 --jit_tls
->active_jit_methods
;
1970 JitCompilationEntry
*entry
= find_method (method
, target_domain
);
1971 g_assert (entry
); // It would be weird to fail
1974 if (entry
->threads_waiting
) {
1975 g_assert (entry
->has_cond
);
1976 mono_coop_cond_broadcast (&entry
->cond
);
1979 if (--entry
->compilation_count
== 0) {
1980 g_ptr_array_remove (compilation_data
.in_flight_methods
, entry
);
1981 unref_jit_entry (entry
);
1984 unlock_compilation_data ();
1989 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
1991 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
1993 gpointer code
= NULL
, p
;
1995 MonoJitICallInfo
*callinfo
= NULL
;
1996 WrapperInfo
*winfo
= NULL
;
2000 #ifdef ENABLE_INTERPRETER
2001 if (mono_use_interpreter
&& !jit_only
) {
2002 code
= mono_interp_create_method_pointer (method
, error
);
2009 /* Should be handled by the caller */
2010 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
2013 * ICALL wrappers are handled specially, since there is only one copy of them
2014 * shared by all appdomains.
2016 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2017 winfo
= mono_marshal_get_wrapper_info (method
);
2018 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
2019 callinfo
= mono_find_jit_icall_by_addr (winfo
->d
.icall
.func
);
2020 g_assert (callinfo
);
2022 /* Must be domain neutral since there is only one copy */
2023 opt
|= MONO_OPT_SHARED
;
2025 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2026 opt
&= ~MONO_OPT_SHARED
;
2029 if (opt
& MONO_OPT_SHARED
)
2030 target_domain
= mono_get_root_domain ();
2032 target_domain
= domain
;
2034 if (method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2035 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2038 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
2039 MonoGenericContext
*ctx
= NULL
;
2040 if (method
->is_inflated
)
2041 ctx
= mono_method_get_context (method
);
2042 method
= info
->d
.synchronized_inner
.method
;
2044 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2045 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
2051 info
= lookup_method (target_domain
, method
);
2053 /* We can't use a domain specific method in another domain */
2054 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2057 mono_jit_stats
.methods_lookups
++;
2058 vtable
= mono_class_vtable_full (domain
, method
->klass
, error
);
2062 if (!mono_runtime_class_init_full (vtable
, error
))
2064 return mono_create_ftnptr (target_domain
, info
->code_start
);
2068 #ifdef MONO_USE_AOT_COMPILER
2069 if (opt
& MONO_OPT_AOT
) {
2070 MonoDomain
*domain
= NULL
;
2072 if (mono_aot_mode
== MONO_AOT_MODE_INTERP
&& method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2073 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2075 if (info
->subtype
== WRAPPER_SUBTYPE_INTERP_IN
)
2076 /* AOT'd wrappers for interp must be owned by root domain */
2077 domain
= mono_get_root_domain ();
2081 domain
= mono_domain_get ();
2083 mono_class_init (method
->klass
);
2085 if ((code
= mono_aot_get_method_checked (domain
, method
, error
))) {
2088 if (mono_gc_is_critical_method (method
)) {
2090 * The suspend code needs to be able to lookup these methods by ip in async context,
2091 * so preload their jit info.
2093 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, code
);
2098 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2099 * This is not a problem, since it will be initialized when the method is first
2100 * called by init_method ().
2102 if (!mono_llvm_only
) {
2103 vtable
= mono_class_vtable (domain
, method
->klass
);
2105 if (!mono_runtime_class_init_full (vtable
, error
))
2114 if (!code
&& mono_llvm_only
) {
2115 if (method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2116 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2118 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
) {
2120 * These wrappers are only created for signatures which are in the program, but
2121 * sometimes we load methods too eagerly and have to create them even if they
2122 * will never be called.
2124 return no_gsharedvt_in_wrapper
;
2130 if (wait_or_register_method_to_compile (method
, target_domain
))
2132 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2133 unregister_method_for_compile (method
, target_domain
);
2135 if (!mono_error_ok (error
))
2138 if (!code
&& mono_llvm_only
) {
2139 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2140 g_assert_not_reached ();
2146 if (method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
) {
2150 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2152 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2156 p
= mono_create_ftnptr (target_domain
, code
);
2159 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2160 mono_loader_lock ();
2162 if (!callinfo
->wrapper
) {
2163 callinfo
->wrapper
= p
;
2164 mono_register_jit_icall_wrapper (callinfo
, p
);
2167 mono_loader_unlock ();
2174 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2178 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2183 * mono_jit_compile_method_jit_only:
2185 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2188 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2192 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2196 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2198 invalidated_delegate_trampoline (char *desc
)
2200 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2201 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2207 * mono_jit_free_method:
2209 * Free all memory allocated by the JIT for METHOD.
2212 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2214 MonoJitDynamicMethodInfo
*ji
;
2215 gboolean destroy
= TRUE
;
2216 GHashTableIter iter
;
2217 MonoJumpList
*jlist
;
2219 g_assert (method
->dynamic
);
2221 mono_domain_lock (domain
);
2222 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2223 mono_domain_unlock (domain
);
2228 mono_debug_remove_method (method
, domain
);
2229 mono_lldb_remove_method (domain
, method
, ji
);
2231 mono_domain_lock (domain
);
2232 g_hash_table_remove (domain_jit_info (domain
)->dynamic_code_hash
, method
);
2233 mono_domain_jit_code_hash_lock (domain
);
2234 mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2235 mono_domain_jit_code_hash_unlock (domain
);
2236 g_hash_table_remove (domain_jit_info (domain
)->jump_trampoline_hash
, method
);
2238 /* requires the domain lock - took above */
2239 mono_conc_hashtable_remove (domain_jit_info (domain
)->runtime_invoke_hash
, method
);
2241 /* Remove jump targets in this method */
2242 g_hash_table_iter_init (&iter
, domain_jit_info (domain
)->jump_target_hash
);
2243 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2244 GSList
*tmp
, *remove
;
2247 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2248 guint8
*ip
= (guint8
*)tmp
->data
;
2250 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2251 remove
= g_slist_prepend (remove
, tmp
);
2253 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2254 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2256 g_slist_free (remove
);
2258 mono_domain_unlock (domain
);
2260 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2261 if (debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2263 * Instead of freeing the code, change it to call an error routine
2264 * so people can fix their code.
2266 char *type
= mono_type_full_name (&method
->klass
->byval_arg
);
2267 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2270 mono_arch_invalidate_method (ji
->ji
, invalidated_delegate_trampoline
, type_and_method
);
2276 * This needs to be done before freeing code_mp, since the code address is the
2277 * key in the table, so if we free the code_mp first, another thread can grab the
2278 * same code address and replace our entry in the table.
2280 mono_jit_info_table_remove (domain
, ji
->ji
);
2283 mono_code_manager_destroy (ji
->code_mp
);
2288 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2290 MonoDomain
*target_domain
;
2293 if (default_opt
& MONO_OPT_SHARED
)
2294 target_domain
= mono_get_root_domain ();
2296 target_domain
= domain
;
2298 info
= lookup_method (target_domain
, method
);
2300 /* We can't use a domain specific method in another domain */
2301 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2302 mono_jit_stats
.methods_lookups
++;
2305 return info
->code_start
;
2314 static guint32 bisect_opt
= 0;
2315 static GHashTable
*bisect_methods_hash
= NULL
;
2318 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2321 char method_name
[2048];
2324 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2325 g_assert (bisect_methods_hash
);
2327 file
= fopen (method_list_filename
, "r");
2330 while (fgets (method_name
, sizeof (method_name
), file
)) {
2331 size_t len
= strlen (method_name
);
2333 g_assert (method_name
[len
- 1] == '\n');
2334 method_name
[len
- 1] = 0;
2335 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2337 g_assert (feof (file
));
2340 gboolean mono_do_single_method_regression
= FALSE
;
2341 guint32 mono_single_method_regression_opt
= 0;
2342 MonoMethod
*mono_current_single_method
;
2343 GSList
*mono_single_method_list
;
2344 GHashTable
*mono_single_method_hash
;
2347 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 default_opt
)
2351 if (bisect_methods_hash
) {
2352 char *name
= mono_method_full_name (method
, TRUE
);
2353 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2356 return default_opt
| bisect_opt
;
2358 if (!mono_do_single_method_regression
)
2360 if (!mono_current_single_method
) {
2361 if (!mono_single_method_hash
)
2362 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2363 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2364 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2365 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2369 if (method
== mono_current_single_method
)
2370 return mono_single_method_regression_opt
;
2375 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2377 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
2382 gpointer compiled_method
;
2383 gpointer runtime_invoke
;
2385 MonoDynCallInfo
*dyn_call_info
;
2386 MonoClass
*ret_box_class
;
2387 MonoMethodSignature
*sig
;
2388 gboolean gsharedvt_invoke
;
2389 gpointer
*wrapper_arg
;
2390 } RuntimeInvokeInfo
;
2392 static RuntimeInvokeInfo
*
2393 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, MonoError
*error
)
2396 RuntimeInvokeInfo
*info
;
2398 info
= g_new0 (RuntimeInvokeInfo
, 1);
2399 info
->compiled_method
= compiled_method
;
2400 if (mono_llvm_only
&& method
->string_ctor
)
2401 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
2403 info
->sig
= mono_method_signature (method
);
2405 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
2406 info
->vtable
= mono_class_vtable_full (domain
, method
->klass
, error
);
2407 if (!mono_error_ok (error
))
2409 g_assert (info
->vtable
);
2411 MonoMethodSignature
*sig
= info
->sig
;
2415 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2416 * in full-aot mode, so we use a slower, but more generic wrapper if
2417 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2419 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2420 if (!mono_llvm_only
&& (mono_aot_only
|| debug_options
.dyn_runtime_invoke
)) {
2421 gboolean supported
= TRUE
;
2424 if (method
->string_ctor
)
2425 sig
= mono_marshal_get_string_ctor_signature (method
);
2427 for (i
= 0; i
< sig
->param_count
; ++i
) {
2428 MonoType
*t
= sig
->params
[i
];
2430 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
2434 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
2438 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
2442 ret_type
= sig
->ret
;
2443 switch (ret_type
->type
) {
2444 case MONO_TYPE_VOID
:
2456 case MONO_TYPE_BOOLEAN
:
2457 case MONO_TYPE_CHAR
:
2460 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2463 info
->ret_box_class
= mono_defaults
.int_class
;
2465 case MONO_TYPE_STRING
:
2466 case MONO_TYPE_CLASS
:
2467 case MONO_TYPE_ARRAY
:
2468 case MONO_TYPE_SZARRAY
:
2469 case MONO_TYPE_OBJECT
:
2471 case MONO_TYPE_GENERICINST
:
2472 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
2473 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2475 case MONO_TYPE_VALUETYPE
:
2476 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2479 g_assert_not_reached ();
2483 if (!info
->dyn_call_info
) {
2484 if (mono_llvm_only
) {
2485 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2486 g_assert_not_reached ();
2488 info
->gsharedvt_invoke
= TRUE
;
2489 if (!callee_gsharedvt
) {
2490 /* Invoke a gsharedvt out wrapper instead */
2491 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2492 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2494 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
2495 info
->wrapper_arg
[0] = mini_add_method_wrappers_llvmonly (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
2497 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2498 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2499 g_free (wrapper_sig
);
2501 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
2502 if (!mono_error_ok (error
)) {
2507 /* Gsharedvt methods can be invoked the same way */
2508 /* The out wrapper has the same signature as the compiled gsharedvt method */
2509 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2511 info
->wrapper_arg
= mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
;
2513 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2514 g_free (wrapper_sig
);
2517 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
2518 if (!mono_error_ok (error
)) {
2528 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2530 MonoMethodSignature
*sig
= info
->sig
;
2531 MonoDomain
*domain
= mono_domain_get ();
2532 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2534 gpointer retval_ptr
;
2535 guint8 retval
[256];
2536 gpointer
*param_refs
;
2541 g_assert (info
->gsharedvt_invoke
);
2544 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2545 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2546 * signatures, so we only have to generate runtime invoke wrappers for these
2548 * This code also handles invocation of gsharedvt methods directly, no
2549 * out wrappers are used in that case.
2551 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2552 param_refs
= (gpointer
*)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2555 * The runtime invoke wrappers expects pointers to primitive types, so have to
2559 args
[pindex
++] = &obj
;
2560 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
2561 retval_ptr
= (gpointer
)&retval
;
2562 args
[pindex
++] = &retval_ptr
;
2564 for (i
= 0; i
< sig
->param_count
; ++i
) {
2565 MonoType
*t
= sig
->params
[i
];
2567 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
2568 MonoClass
*klass
= mono_class_from_mono_type (t
);
2569 guint8
*nullable_buf
;
2572 size
= mono_class_value_size (klass
, NULL
);
2573 nullable_buf
= g_alloca (size
);
2574 g_assert (nullable_buf
);
2576 /* The argument pointed to by params [i] is either a boxed vtype or null */
2577 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
2578 params
[i
] = nullable_buf
;
2581 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
2582 param_refs
[i
] = params
[i
];
2583 params
[i
] = &(param_refs
[i
]);
2585 args
[pindex
++] = ¶ms
[i
];
2587 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2588 args
[pindex
++] = &info
->wrapper_arg
;
2590 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2592 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
2596 if (sig
->ret
->type
!= MONO_TYPE_VOID
&& info
->ret_box_class
)
2597 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2599 return *(MonoObject
**)retval
;
2603 * mono_jit_runtime_invoke:
2604 * \param method: the method to invoke
2605 * \param obj: this pointer
2606 * \param params: array of parameter values.
2607 * \param exc: Set to the exception raised in the managed method.
2608 * \param error: error or caught exception object
2609 * If \p exc is NULL, \p error is thrown instead.
2610 * If coop is enabled, \p exc argument is ignored -
2611 * all exceptions are caught and propagated through \p error
2614 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2616 MonoMethod
*invoke
, *callee
;
2617 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2618 MonoDomain
*domain
= mono_domain_get ();
2619 MonoJitDomainInfo
*domain_info
;
2620 RuntimeInvokeInfo
*info
, *info2
;
2621 MonoJitInfo
*ji
= NULL
;
2622 gboolean callee_gsharedvt
= FALSE
;
2624 #ifdef ENABLE_INTERPRETER
2625 if (mono_use_interpreter
)
2626 return mono_interp_runtime_invoke (method
, obj
, params
, exc
, error
);
2631 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
2632 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2636 domain_info
= domain_jit_info (domain
);
2638 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
2641 if (mono_security_core_clr_enabled ()) {
2643 * This might be redundant since mono_class_vtable () already does this,
2644 * but keep it just in case for moonlight.
2646 mono_class_setup_vtable (method
->klass
);
2647 if (mono_class_has_failure (method
->klass
)) {
2648 mono_error_set_for_class_failure (error
, method
->klass
);
2650 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
2655 gpointer compiled_method
;
2658 if (method
->klass
->rank
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2659 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2661 * Array Get/Set/Address methods. The JIT implements them using inline code
2662 * inside the runtime invoke wrappers, so no need to compile them.
2664 if (mono_aot_only
) {
2666 * Call a wrapper, since the runtime invoke wrapper was not generated.
2668 MonoMethod
*wrapper
;
2670 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
2671 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
2679 compiled_method
= mono_jit_compile_method (callee
, error
);
2680 if (!compiled_method
) {
2681 g_assert (!mono_error_ok (error
));
2685 if (mono_llvm_only
) {
2686 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
2687 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2688 if (callee_gsharedvt
)
2689 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji
)));
2692 if (!callee_gsharedvt
)
2693 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
2695 compiled_method
= NULL
;
2698 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, error
);
2699 if (!mono_error_ok (error
))
2702 mono_domain_lock (domain
);
2703 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
2704 mono_domain_unlock (domain
);
2712 * We need this here because mono_marshal_get_runtime_invoke can place
2713 * the helper method in System.Object and not the target class.
2715 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
2717 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
2721 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2722 we always catch the exception and propagate it through the MonoError */
2723 gboolean catchExcInMonoError
=
2724 (exc
== NULL
) && mono_threads_is_coop_enabled ();
2725 MonoObject
*invoke_exc
= NULL
;
2726 if (catchExcInMonoError
)
2729 /* The wrappers expect this to be initialized to NULL */
2733 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2734 if (info
->dyn_call_info
) {
2735 MonoMethodSignature
*sig
= mono_method_signature (method
);
2737 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
;
2740 guint8 retval
[256];
2742 if (!dyn_runtime_invoke
) {
2743 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
2744 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method (invoke
, error
);
2745 if (!mono_error_ok (error
))
2749 /* Convert the arguments to the format expected by start_dyn_call () */
2750 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
2753 args
[pindex
++] = &obj
;
2754 for (i
= 0; i
< sig
->param_count
; ++i
) {
2755 MonoType
*t
= sig
->params
[i
];
2758 args
[pindex
++] = ¶ms
[i
];
2759 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
2760 args
[pindex
++] = ¶ms
[i
];
2762 args
[pindex
++] = params
[i
];
2766 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2768 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
, sizeof (buf
));
2770 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
2771 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
2773 if (catchExcInMonoError
&& *exc
!= NULL
) {
2774 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
2778 if (info
->ret_box_class
)
2779 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2781 return *(MonoObject
**)retval
;
2787 if (mono_llvm_only
) {
2788 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
2792 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2794 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
2796 if (catchExcInMonoError
&& *exc
!= NULL
)
2797 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
2806 typedef gpointer (*IMTTrampFunc
) (gpointer
*arg
, MonoMethod
*imt_method
);
2809 * mini_llvmonly_initial_imt_tramp:
2811 * This function is called the first time a call is made through an IMT trampoline.
2812 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2815 mini_llvmonly_initial_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
2817 IMTTrampInfo
*info
= (IMTTrampInfo
*)arg
;
2822 mono_vtable_build_imt_slot (info
->vtable
, info
->slot
);
2824 imt
= (gpointer
*)info
->vtable
;
2825 imt
-= MONO_IMT_SIZE
;
2827 /* Return what the real IMT trampoline returns */
2828 ftndesc
= imt
[info
->slot
];
2831 if (func
== (IMTTrampFunc
)mini_llvmonly_initial_imt_tramp
)
2832 /* Happens when the imt slot contains only a generic virtual method */
2834 return func ((gpointer
*)ftndesc
[1], imt_method
);
2837 /* This is called indirectly through an imt slot. */
2839 mono_llvmonly_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
2843 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2844 while (arg
[i
] && arg
[i
] != imt_method
)
2851 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2853 mono_llvmonly_imt_tramp_1 (gpointer
*arg
, MonoMethod
*imt_method
)
2855 //g_assert (arg [0] == imt_method);
2860 mono_llvmonly_imt_tramp_2 (gpointer
*arg
, MonoMethod
*imt_method
)
2862 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2863 if (arg
[0] == imt_method
)
2870 mono_llvmonly_imt_tramp_3 (gpointer
*arg
, MonoMethod
*imt_method
)
2872 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2873 if (arg
[0] == imt_method
)
2875 else if (arg
[2] == imt_method
)
2882 * A version of the imt trampoline used for generic virtual/variant iface methods.
2883 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2884 * in the search table. The original JIT code had a 'fallback' trampoline it could
2885 * call, but we can't do that, so we just return NULL, and the compiled code
2889 mono_llvmonly_fallback_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
2893 while (arg
[i
] && arg
[i
] != imt_method
)
2902 mono_llvmonly_get_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
, gpointer fail_tramp
)
2906 int i
, index
, real_count
;
2907 gboolean virtual_generic
= FALSE
;
2910 * Create an array which is passed to the imt trampoline functions.
2911 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2915 for (i
= 0; i
< count
; ++i
) {
2916 MonoIMTCheckItem
*item
= imt_entries
[i
];
2918 if (item
->is_equals
)
2920 if (item
->has_target_code
)
2921 virtual_generic
= TRUE
;
2925 * Initialize all vtable entries reachable from this imt slot, so the compiled
2926 * code doesn't have to check it.
2928 for (i
= 0; i
< count
; ++i
) {
2929 MonoIMTCheckItem
*item
= imt_entries
[i
];
2932 if (!item
->is_equals
|| item
->has_target_code
)
2934 vt_slot
= item
->value
.vtable_slot
;
2935 mono_init_vtable_slot (vtable
, vt_slot
);
2938 /* Save the entries into an array */
2939 buf
= (void **)mono_domain_alloc (domain
, (real_count
+ 1) * 2 * sizeof (gpointer
));
2941 for (i
= 0; i
< count
; ++i
) {
2942 MonoIMTCheckItem
*item
= imt_entries
[i
];
2944 if (!item
->is_equals
)
2947 g_assert (item
->key
);
2948 buf
[(index
* 2)] = item
->key
;
2949 if (item
->has_target_code
)
2950 buf
[(index
* 2) + 1] = item
->value
.target_code
;
2952 buf
[(index
* 2) + 1] = vtable
->vtable
[item
->value
.vtable_slot
];
2955 buf
[(index
* 2)] = NULL
;
2956 buf
[(index
* 2) + 1] = fail_tramp
;
2959 * Return a function descriptor for a C function with 'buf' as its argument.
2960 * It will by called by JITted code.
2962 res
= (void **)mono_domain_alloc (domain
, 2 * sizeof (gpointer
));
2963 switch (real_count
) {
2965 res
[0] = mono_llvmonly_imt_tramp_1
;
2968 res
[0] = mono_llvmonly_imt_tramp_2
;
2971 res
[0] = mono_llvmonly_imt_tramp_3
;
2974 res
[0] = mono_llvmonly_imt_tramp
;
2977 if (virtual_generic
|| fail_tramp
)
2978 res
[0] = mono_llvmonly_fallback_imt_tramp
;
2984 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
2986 MonoException
*exc
= NULL
;
2988 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
2989 MONO_SIG_HANDLER_GET_CONTEXT
;
2991 ji
= mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
2993 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
2995 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2996 if (mono_arch_is_int_overflow (ctx
, info
))
2998 * The spec says this throws ArithmeticException, but MS throws the derived
2999 * OverflowException.
3001 exc
= mono_get_exception_overflow ();
3003 exc
= mono_get_exception_divide_by_zero ();
3005 exc
= mono_get_exception_divide_by_zero ();
3009 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3012 mono_handle_native_crash ("SIGFPE", ctx
, info
);
3013 if (mono_do_crash_chaining
) {
3014 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3019 mono_arch_handle_exception (ctx
, exc
);
3022 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3025 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler
)
3027 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3028 MONO_SIG_HANDLER_GET_CONTEXT
;
3030 if (mono_runtime_get_no_exec ())
3034 mono_handle_native_crash ("SIGILL", ctx
, info
);
3035 if (mono_do_crash_chaining
) {
3036 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3040 g_assert_not_reached ();
3043 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3044 #define HAVE_SIG_INFO
3047 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3050 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
3051 gpointer fault_addr
= NULL
;
3052 #ifdef HAVE_SIG_INFO
3053 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3057 MONO_SIG_HANDLER_GET_CONTEXT
;
3059 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3060 if (mono_arch_is_single_step_event (info
, ctx
)) {
3061 mono_debugger_agent_single_step_event (ctx
);
3063 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3064 mono_debugger_agent_breakpoint_hit (ctx
);
3069 #if defined(HAVE_SIG_INFO)
3070 #if !defined(HOST_WIN32)
3071 fault_addr
= info
->si_addr
;
3072 if (mono_aot_is_pagefault (info
->si_addr
)) {
3073 mono_aot_handle_pagefault (info
->si_addr
);
3078 /* The thread might no be registered with the runtime */
3079 if (!mono_domain_get () || !jit_tls
) {
3080 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3082 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3083 if (mono_do_crash_chaining
) {
3084 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3090 ji
= mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3092 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3093 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3096 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3097 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3098 fault_addr
= info
->si_addr
;
3099 if (fault_addr
== NULL
) {
3102 mono_sigctx_to_monoctx (ctx
, &mctx
);
3104 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3108 if (jit_tls
->stack_size
&&
3109 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3111 * The hard-guard page has been hit: there is not much we can do anymore
3112 * Print a hopefully clear message and abort.
3114 mono_handle_hard_stack_ovf (jit_tls
, ji
, ctx
, (guint8
*)info
->si_addr
);
3115 g_assert_not_reached ();
3117 /* The original handler might not like that it is executed on an altstack... */
3118 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3121 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3126 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3129 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3131 if (mono_do_crash_chaining
) {
3132 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3137 mono_arch_handle_exception (ctx
, NULL
);
3141 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3144 MONO_SIG_HANDLER_GET_CONTEXT
;
3146 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3148 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3150 mono_arch_handle_exception (ctx
, exc
);
3152 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3155 #ifndef DISABLE_REMOTING
3156 /* mono_jit_create_remoting_trampoline:
3157 * @method: pointer to the method info
3159 * Creates a trampoline which calls the remoting functions. This
3160 * is used in the vtable of transparent proxies.
3162 * Returns: a pointer to the newly created code
3165 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3168 guint8
*addr
= NULL
;
3172 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature (method
)->generic_param_count
) {
3173 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3177 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3178 (mono_method_signature (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3179 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
);
3182 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3183 return_val_if_nok (error
, NULL
);
3184 return mono_get_addr_from_ftnptr (addr
);
3188 static G_GNUC_UNUSED
void
3189 no_imt_trampoline (void)
3191 g_assert_not_reached ();
3194 static G_GNUC_UNUSED
void
3195 no_vcall_trampoline (void)
3197 g_assert_not_reached ();
3200 static gpointer
*vtable_trampolines
;
3201 static int vtable_trampolines_size
;
3204 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3206 int index
= slot_index
+ MONO_IMT_SIZE
;
3208 if (mono_llvm_only
) {
3209 if (slot_index
< 0) {
3210 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3211 // FIXME: Memory management
3212 gpointer
*ftndesc
= g_malloc (2 * sizeof (gpointer
));
3213 IMTTrampInfo
*info
= g_new0 (IMTTrampInfo
, 1);
3216 ftndesc
[0] = mini_llvmonly_initial_imt_tramp
;
3218 mono_memory_barrier ();
3225 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3226 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3228 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3232 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3233 while (new_size
<= index
)
3235 new_table
= g_new0 (gpointer
, new_size
);
3237 if (vtable_trampolines
)
3238 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3239 g_free (vtable_trampolines
);
3240 mono_memory_barrier ();
3241 vtable_trampolines
= (void **)new_table
;
3242 vtable_trampolines_size
= new_size
;
3247 if (!vtable_trampolines
[index
])
3248 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3249 return vtable_trampolines
[index
];
3253 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3255 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3259 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3264 gpointer
*imt
= (gpointer
*)vt
;
3265 imt
-= MONO_IMT_SIZE
;
3267 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3271 is_callee_gsharedvt_variable (gpointer addr
)
3274 gboolean callee_gsharedvt
;
3276 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
3278 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3279 if (callee_gsharedvt
)
3280 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji
)));
3281 return callee_gsharedvt
;
3285 mini_get_delegate_arg (MonoMethod
*method
, gpointer method_ptr
)
3287 gpointer arg
= NULL
;
3289 if (mono_method_needs_static_rgctx_invoke (method
, FALSE
))
3290 arg
= mini_method_get_rgctx (method
);
3293 * Avoid adding gsharedvt in wrappers since they might not exist if
3294 * this delegate is called through a gsharedvt delegate invoke wrapper.
3295 * Instead, encode that the method is gsharedvt in del->extra_arg,
3296 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3298 if (method
->is_inflated
&& is_callee_gsharedvt_variable (method_ptr
)) {
3299 g_assert ((((mgreg_t
)arg
) & 1) == 0);
3300 arg
= (gpointer
)(((mgreg_t
)arg
) | 1);
3306 mini_init_delegate (MonoDelegate
*del
)
3309 del
->extra_arg
= mini_get_delegate_arg (del
->method
, del
->method_ptr
);
3310 #ifdef ENABLE_INTERPRETER
3311 if (mono_use_interpreter
)
3312 mono_interp_init_delegate (del
);
3317 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3321 abs_offset
= offset
;
3323 abs_offset
= - abs_offset
;
3324 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ SIZEOF_VOID_P
);
3328 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3330 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3333 static guint8
**cache
= NULL
;
3334 static int cache_size
= 0;
3339 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3342 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3343 is_interface
= mono_class_is_interface (method
->klass
);
3344 load_imt_reg
= is_virtual_generic
|| is_interface
;
3347 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * SIZEOF_VOID_P
;
3349 offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (SIZEOF_VOID_P
));
3351 idx
= (offset
/ SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3352 g_assert (idx
>= 0);
3354 /* Resize the cache to idx + 1 */
3355 if (cache_size
< idx
+ 1) {
3357 if (cache_size
< idx
+ 1) {
3359 int new_cache_size
= idx
+ 1;
3361 new_cache
= g_new0 (guint8
*, new_cache_size
);
3363 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3366 mono_memory_barrier ();
3368 cache_size
= new_cache_size
;
3376 /* FIXME Support more cases */
3377 if (mono_aot_only
) {
3378 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3379 g_assert (cache
[idx
]);
3381 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3387 * mini_parse_debug_option:
3388 * @option: The option to parse.
3390 * Parses debug options for the mono runtime. The options are the same as for
3391 * the MONO_DEBUG environment variable.
3395 mini_parse_debug_option (const char *option
)
3397 if (!strcmp (option
, "handle-sigint"))
3398 debug_options
.handle_sigint
= TRUE
;
3399 else if (!strcmp (option
, "keep-delegates"))
3400 debug_options
.keep_delegates
= TRUE
;
3401 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3402 debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3403 else if (!strcmp (option
, "collect-pagefault-stats"))
3404 debug_options
.collect_pagefault_stats
= TRUE
;
3405 else if (!strcmp (option
, "break-on-unverified"))
3406 debug_options
.break_on_unverified
= TRUE
;
3407 else if (!strcmp (option
, "no-gdb-backtrace"))
3408 debug_options
.no_gdb_backtrace
= TRUE
;
3409 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
3410 debug_options
.suspend_on_native_crash
= TRUE
;
3411 else if (!strcmp (option
, "suspend-on-exception"))
3412 debug_options
.suspend_on_exception
= TRUE
;
3413 else if (!strcmp (option
, "suspend-on-unhandled"))
3414 debug_options
.suspend_on_unhandled
= TRUE
;
3415 else if (!strcmp (option
, "dont-free-domains"))
3416 mono_dont_free_domains
= TRUE
;
3417 else if (!strcmp (option
, "dyn-runtime-invoke"))
3418 debug_options
.dyn_runtime_invoke
= TRUE
;
3419 else if (!strcmp (option
, "gdb"))
3420 debug_options
.gdb
= TRUE
;
3421 else if (!strcmp (option
, "lldb"))
3422 debug_options
.lldb
= TRUE
;
3423 else if (!strcmp (option
, "explicit-null-checks"))
3424 debug_options
.explicit_null_checks
= TRUE
;
3425 else if (!strcmp (option
, "gen-seq-points"))
3426 debug_options
.gen_sdb_seq_points
= TRUE
;
3427 else if (!strcmp (option
, "gen-compact-seq-points"))
3428 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3429 else if (!strcmp (option
, "no-compact-seq-points"))
3430 debug_options
.no_seq_points_compact_data
= TRUE
;
3431 else if (!strcmp (option
, "single-imm-size"))
3432 debug_options
.single_imm_size
= TRUE
;
3433 else if (!strcmp (option
, "init-stacks"))
3434 debug_options
.init_stacks
= TRUE
;
3435 else if (!strcmp (option
, "casts"))
3436 debug_options
.better_cast_details
= TRUE
;
3437 else if (!strcmp (option
, "soft-breakpoints"))
3438 debug_options
.soft_breakpoints
= TRUE
;
3439 else if (!strcmp (option
, "check-pinvoke-callconv"))
3440 debug_options
.check_pinvoke_callconv
= TRUE
;
3441 else if (!strcmp (option
, "use-fallback-tls"))
3442 debug_options
.use_fallback_tls
= TRUE
;
3443 else if (!strcmp (option
, "debug-domain-unload"))
3444 mono_enable_debug_domain_unload (TRUE
);
3445 else if (!strcmp (option
, "partial-sharing"))
3446 mono_set_partial_sharing_supported (TRUE
);
3447 else if (!strcmp (option
, "align-small-structs"))
3448 mono_align_small_structs
= TRUE
;
3449 else if (!strcmp (option
, "native-debugger-break"))
3450 debug_options
.native_debugger_break
= TRUE
;
3451 else if (!strcmp (option
, "disable_omit_fp"))
3452 debug_options
.disable_omit_fp
= TRUE
;
3460 mini_parse_debug_options (void)
3462 char *options
= g_getenv ("MONO_DEBUG");
3463 gchar
**args
, **ptr
;
3468 args
= g_strsplit (options
, ",", -1);
3471 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
3472 const char *arg
= *ptr
;
3474 if (!mini_parse_debug_option (arg
)) {
3475 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
3476 fprintf (stderr
, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
3485 mini_get_debug_options (void)
3487 return &debug_options
;
3491 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
3493 #if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3496 gpointer
* desc
= NULL
;
3498 if ((desc
= g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
3500 # if defined(__ppc64__) || defined(__powerpc64__)
3502 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
3508 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
3514 mini_get_addr_from_ftnptr (gpointer descr
)
3516 #if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3517 return *(gpointer
*)descr
;
3524 register_jit_stats (void)
3526 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
3527 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
3528 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
3529 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
3530 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_method_to_ir
);
3531 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses
);
3532 mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_out_of_line_bblock
);
3533 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_long_opts
);
3534 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_typechecks
);
3535 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop
);
3536 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_emulate_ops
);
3537 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches
);
3538 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs
);
3539 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce
);
3540 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_alias_analysis
);
3541 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_if_conversion
);
3542 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_bb_ordering
);
3543 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compile_dominator_info
);
3544 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compute_natural_loops
);
3545 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_insert_safepoints
);
3546 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_compute
);
3547 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_cprop
);
3548 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_deadce
);
3549 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_perform_abc_removal
);
3550 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_remove
);
3551 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop2
);
3552 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs2
);
3553 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce2
);
3554 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches2
);
3555 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_vtype_opts
);
3556 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_array_access_opts
);
3557 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses2
);
3558 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_analyze_liveness
);
3559 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_linear_scan
);
3560 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_arch_allocate_vars
);
3561 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_spill_global_vars
);
3562 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop3
);
3563 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce3
);
3564 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_codegen
);
3565 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_create_jit_info
);
3566 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_gc_create_gc_map
);
3567 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_save_seq_point_info
);
3568 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_time
);
3569 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.basic_blocks
);
3570 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.max_basic_blocks
);
3571 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocate_var
);
3572 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.code_reallocs
);
3573 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_code_size
);
3574 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_seq_points_size
);
3575 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlineable_methods
);
3576 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlined_methods
);
3577 mono_counters_register ("Regvars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.regvars
);
3578 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.locals_stack_size
);
3579 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_lookups
);
3580 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.cil_code_size
);
3581 mono_counters_register ("Native code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.native_code_size
);
3582 mono_counters_register ("Aliases found", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_found
);
3583 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_removed
);
3584 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.loads_eliminated
);
3585 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.stores_eliminated
);
3586 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.optimized_divisions
);
3589 static void runtime_invoke_info_free (gpointer value
);
3592 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
3594 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
3595 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
3597 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
3601 class_method_pair_hash (gconstpointer data
)
3603 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
3605 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
3609 mini_create_jit_domain_info (MonoDomain
*domain
)
3611 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
3613 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3614 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3615 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
3616 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3617 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
3618 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
3619 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3620 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
3621 mono_jit_code_hash_init (&info
->interp_code_hash
);
3623 domain
->runtime_info
= info
;
3627 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
3629 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
3630 g_slist_free (jlist
->list
);
3634 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
3636 GSList
*list
= (GSList
*)value
;
3637 g_slist_free (list
);
3641 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
3643 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
3644 mono_code_manager_destroy (di
->code_mp
);
3649 runtime_invoke_info_free (gpointer value
)
3651 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
3653 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3654 if (info
->dyn_call_info
)
3655 mono_arch_dyn_call_free (info
->dyn_call_info
);
3661 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
3663 g_slist_free (value
);
3667 mini_free_jit_domain_info (MonoDomain
*domain
)
3669 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3671 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
3672 g_hash_table_destroy (info
->jump_target_hash
);
3673 if (info
->jump_target_got_slot_hash
) {
3674 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
3675 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
3677 if (info
->dynamic_code_hash
) {
3678 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
3679 g_hash_table_destroy (info
->dynamic_code_hash
);
3681 if (info
->method_code_hash
)
3682 g_hash_table_destroy (info
->method_code_hash
);
3683 g_hash_table_destroy (info
->jump_trampoline_hash
);
3684 g_hash_table_destroy (info
->jit_trampoline_hash
);
3685 g_hash_table_destroy (info
->delegate_trampoline_hash
);
3686 if (info
->static_rgctx_trampoline_hash
)
3687 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
3688 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
3689 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
3690 g_hash_table_destroy (info
->seq_points
);
3691 g_hash_table_destroy (info
->arch_seq_points
);
3692 if (info
->agent_info
)
3693 mono_debugger_agent_free_domain_info (domain
);
3694 if (info
->gsharedvt_arg_tramp_hash
)
3695 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
3696 if (info
->llvm_jit_callees
) {
3697 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
3698 g_hash_table_destroy (info
->llvm_jit_callees
);
3700 mono_internal_hash_table_destroy (&info
->interp_code_hash
);
3702 mono_llvm_free_domain_info (domain
);
3705 g_free (domain
->runtime_info
);
3706 domain
->runtime_info
= NULL
;
3709 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3712 code_manager_chunk_new (void *chunk
, int size
)
3714 mono_arch_code_chunk_new (chunk
, size
);
3718 code_manager_chunk_destroy (void *chunk
)
3720 mono_arch_code_chunk_destroy (chunk
);
3727 llvm_init_inner (void)
3729 if (!mono_llvm_load (NULL
))
3740 * Load and initialize LLVM support.
3741 * Return TRUE on success.
3744 mini_llvm_init (void)
3747 static gboolean llvm_inited
;
3748 static gboolean init_result
;
3750 mono_loader_lock_if_inited ();
3752 init_result
= llvm_init_inner ();
3755 mono_loader_unlock_if_inited ();
3763 mini_add_profiler_argument (const char *desc
)
3765 if (!profile_options
)
3766 profile_options
= g_ptr_array_new ();
3768 g_ptr_array_add (profile_options
, (gpointer
) desc
);
3772 mini_init (const char *filename
, const char *runtime_version
)
3776 MonoRuntimeCallbacks callbacks
;
3777 MonoThreadInfoRuntimeCallbacks ticallbacks
;
3778 MonoCodeManagerCallbacks code_manager_callbacks
;
3780 MONO_VES_INIT_BEGIN ();
3782 CHECKED_MONO_INIT ();
3784 #if defined(__linux__)
3785 if (access ("/proc/self/maps", F_OK
) != 0) {
3786 g_print ("Mono requires /proc to be mounted.\n");
3791 #ifdef ENABLE_INTERPRETER
3792 mono_interp_init ();
3795 mono_os_mutex_init_recursive (&jit_mutex
);
3797 mono_cross_helpers_run ();
3799 mono_counters_init ();
3803 mini_jit_init_job_control ();
3805 /* Happens when using the embedding interface */
3806 if (!default_opt_set
)
3807 default_opt
= mono_parse_default_optimizations (NULL
);
3809 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3811 mono_set_generic_sharing_vt_supported (TRUE
);
3814 mono_set_generic_sharing_vt_supported (TRUE
);
3817 mono_tls_init_runtime_keys ();
3819 if (!global_codeman
)
3820 global_codeman
= mono_code_manager_new ();
3822 memset (&callbacks
, 0, sizeof (callbacks
));
3823 callbacks
.create_ftnptr
= mini_create_ftnptr
;
3824 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
3825 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
3826 callbacks
.set_cast_details
= mono_set_cast_details
;
3827 callbacks
.debug_log
= mono_debugger_agent_debug_log
;
3828 callbacks
.debug_log_is_enabled
= mono_debugger_agent_debug_log_is_enabled
;
3829 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
3830 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
3831 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
3832 callbacks
.init_delegate
= mini_init_delegate
;
3833 #define JIT_INVOKE_WORKS
3834 #ifdef JIT_INVOKE_WORKS
3835 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
3837 #define JIT_TRAMPOLINES_WORK
3838 #ifdef JIT_TRAMPOLINES_WORK
3839 callbacks
.compile_method
= mono_jit_compile_method
;
3840 callbacks
.create_jump_trampoline
= mono_create_jump_trampoline
;
3841 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
3842 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
3843 callbacks
.free_method
= mono_jit_free_method
;
3844 #ifndef DISABLE_REMOTING
3845 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
3849 mono_install_callbacks (&callbacks
);
3851 memset (&ticallbacks
, 0, sizeof (ticallbacks
));
3852 ticallbacks
.setup_async_callback
= mono_setup_async_callback
;
3853 ticallbacks
.thread_state_init_from_sigctx
= mono_thread_state_init_from_sigctx
;
3854 ticallbacks
.thread_state_init_from_handle
= mono_thread_state_init_from_handle
;
3855 ticallbacks
.thread_state_init
= mono_thread_state_init
;
3858 mono_w32handle_init ();
3861 mono_thread_info_runtime_init (&ticallbacks
);
3863 if (g_hasenv ("MONO_DEBUG")) {
3864 mini_parse_debug_options ();
3867 mono_code_manager_init ();
3869 memset (&code_manager_callbacks
, 0, sizeof (code_manager_callbacks
));
3870 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3871 code_manager_callbacks
.chunk_new
= code_manager_chunk_new
;
3872 code_manager_callbacks
.chunk_destroy
= code_manager_chunk_destroy
;
3874 mono_code_manager_install_callbacks (&code_manager_callbacks
);
3878 mono_arch_cpu_init ();
3882 mono_unwind_init ();
3884 if (mini_get_debug_options ()->lldb
|| g_hasenv ("MONO_LLDB")) {
3885 mono_lldb_init ("");
3886 mono_dont_free_domains
= TRUE
;
3889 #ifdef XDEBUG_ENABLED
3890 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
3892 mono_xdebug_init (mono_xdebug
);
3893 g_free (mono_xdebug
);
3894 /* So methods for multiple domains don't have the same address */
3895 mono_dont_free_domains
= TRUE
;
3896 mono_using_xdebug
= TRUE
;
3897 } else if (mini_get_debug_options ()->gdb
) {
3898 mono_xdebug_init ((char*)"gdb");
3899 mono_dont_free_domains
= TRUE
;
3900 mono_using_xdebug
= TRUE
;
3905 if (mono_use_llvm
) {
3906 if (!mono_llvm_load (NULL
)) {
3907 mono_use_llvm
= FALSE
;
3908 fprintf (stderr
, "Mono Warning: llvm support could not be loaded.\n");
3915 mono_trampolines_init ();
3917 if (default_opt
& MONO_OPT_AOT
)
3920 mono_debugger_agent_init ();
3922 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3923 mono_set_generic_sharing_supported (TRUE
);
3926 mono_thread_info_signals_init ();
3928 #ifndef MONO_CROSS_COMPILE
3929 mono_runtime_install_handlers ();
3931 mono_threads_install_cleanup (mini_thread_cleanup
);
3933 #ifdef JIT_TRAMPOLINES_WORK
3934 mono_install_create_domain_hook (mini_create_jit_domain_info
);
3935 mono_install_free_domain_hook (mini_free_jit_domain_info
);
3937 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
3938 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
3939 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
3941 mono_profiler_state
.context_enable
= mini_profiler_context_enable
;
3942 mono_profiler_state
.context_get_this
= mini_profiler_context_get_this
;
3943 mono_profiler_state
.context_get_argument
= mini_profiler_context_get_argument
;
3944 mono_profiler_state
.context_get_local
= mini_profiler_context_get_local
;
3945 mono_profiler_state
.context_get_result
= mini_profiler_context_get_result
;
3946 mono_profiler_state
.context_free_buffer
= mini_profiler_context_free_buffer
;
3948 if (profile_options
)
3949 for (guint i
= 0; i
< profile_options
->len
; i
++)
3950 mono_profiler_load ((const char *) g_ptr_array_index (profile_options
, i
));
3952 mono_profiler_started ();
3954 if (debug_options
.collect_pagefault_stats
)
3955 mono_aot_set_make_unreadable (TRUE
);
3957 if (runtime_version
)
3958 domain
= mono_init_version (filename
, runtime_version
);
3960 domain
= mono_init_from_assembly (filename
, filename
);
3962 if (mono_aot_only
) {
3963 /* This helps catch code allocation requests */
3964 mono_code_manager_set_read_only (domain
->code_mp
);
3965 mono_marshal_use_aot_wrappers (TRUE
);
3968 if (mono_llvm_only
) {
3969 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline
);
3970 mono_set_always_build_imt_trampolines (TRUE
);
3971 } else if (mono_aot_only
) {
3972 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
3974 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
3977 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3978 mono_arch_finish_init ();
3982 /* This must come after mono_init () in the aot-only case */
3983 mono_exceptions_init ();
3985 /* This should come after mono_init () too */
3989 mono_create_helper_signatures ();
3992 register_jit_stats ();
3994 #define JIT_CALLS_WORK
3995 #ifdef JIT_CALLS_WORK
3996 /* Needs to be called here since register_jit_icall depends on it */
3997 mono_marshal_init ();
3999 mono_arch_register_lowlevel_calls ();
4003 mono_generic_sharing_init ();
4006 #ifdef MONO_ARCH_SIMD_INTRINSICS
4007 mono_simd_intrinsics_init ();
4010 mono_tasklets_init ();
4012 register_trampolines (domain
);
4014 if (mono_compile_aot
)
4016 * Avoid running managed code when AOT compiling, since the platform
4017 * might only support aot-only execution.
4019 mono_runtime_set_no_exec (TRUE
);
4021 mono_mem_account_register_counters ();
4023 #define JIT_RUNTIME_WORKS
4024 #ifdef JIT_RUNTIME_WORKS
4025 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
4026 mono_runtime_init_checked (domain
, mono_thread_start_cb
, mono_thread_attach_cb
, &error
);
4027 mono_error_assert_ok (&error
);
4028 mono_thread_attach (domain
);
4029 MONO_PROFILER_RAISE (thread_name
, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4032 if (mono_profiler_sampling_enabled ())
4033 mono_runtime_setup_stat_profiler ();
4035 MONO_PROFILER_RAISE (runtime_initialized
, ());
4037 MONO_VES_INIT_END ();
4043 register_icalls (void)
4045 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4046 ves_icall_get_frame_info
);
4047 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4048 ves_icall_get_trace
);
4049 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4050 mono_runtime_install_handlers
);
4051 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4052 mono_runtime_cleanup_handlers
);
4054 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
4055 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4056 mono_debugger_agent_unhandled_exception
);
4060 * It's important that we pass `TRUE` as the last argument here, as
4061 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4062 * *did* emit a wrapper, we'd be looking at infinite recursion since
4063 * the wrapper would call the icall which would call the wrapper and
4066 register_icall (mono_profiler_raise_method_enter
, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE
);
4067 register_icall (mono_profiler_raise_method_leave
, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE
);
4069 register_icall (mono_trace_enter_method
, "mono_trace_enter_method", NULL
, TRUE
);
4070 register_icall (mono_trace_leave_method
, "mono_trace_leave_method", NULL
, TRUE
);
4071 register_icall (mono_get_lmf_addr
, "mono_get_lmf_addr", "ptr", TRUE
);
4072 register_icall (mono_jit_thread_attach
, "mono_jit_thread_attach", "ptr ptr", TRUE
);
4073 register_icall (mono_jit_set_domain
, "mono_jit_set_domain", "void ptr", TRUE
);
4074 register_icall (mono_domain_get
, "mono_domain_get", "ptr", TRUE
);
4076 register_icall (mono_llvm_throw_exception
, "mono_llvm_throw_exception", "void object", TRUE
);
4077 register_icall (mono_llvm_rethrow_exception
, "mono_llvm_rethrow_exception", "void object", TRUE
);
4078 register_icall (mono_llvm_resume_exception
, "mono_llvm_resume_exception", "void", TRUE
);
4079 register_icall (mono_llvm_match_exception
, "mono_llvm_match_exception", "int ptr int int", TRUE
);
4080 register_icall (mono_llvm_clear_exception
, "mono_llvm_clear_exception", NULL
, TRUE
);
4081 register_icall (mono_llvm_load_exception
, "mono_llvm_load_exception", "object", TRUE
);
4082 register_icall (mono_llvm_throw_corlib_exception
, "mono_llvm_throw_corlib_exception", "void int", TRUE
);
4083 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4084 register_icall (mono_llvm_set_unhandled_exception_handler
, "mono_llvm_set_unhandled_exception_handler", NULL
, TRUE
);
4086 // FIXME: This is broken
4087 register_icall (mono_debug_personality
, "mono_debug_personality", "int int int ptr ptr ptr", TRUE
);
4090 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE
);
4091 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE
);
4092 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE
);
4093 register_icall (mono_thread_get_undeniable_exception
, "mono_thread_get_undeniable_exception", "object", FALSE
);
4094 register_icall (mono_thread_self_abort
, "mono_thread_self_abort", "void", FALSE
);
4095 register_icall (mono_thread_interruption_checkpoint
, "mono_thread_interruption_checkpoint", "object", FALSE
);
4096 register_icall (mono_thread_force_interruption_checkpoint_noraise
, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE
);
4098 if (mono_threads_is_coop_enabled ())
4099 register_icall (mono_threads_state_poll
, "mono_threads_state_poll", "void", FALSE
);
4101 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4102 register_opcode_emulation (OP_LMUL
, "__emul_lmul", "long long long", mono_llmult
, "mono_llmult", FALSE
);
4103 register_opcode_emulation (OP_LDIV
, "__emul_ldiv", "long long long", mono_lldiv
, "mono_lldiv", FALSE
);
4104 register_opcode_emulation (OP_LDIV_UN
, "__emul_ldiv_un", "long long long", mono_lldiv_un
, "mono_lldiv_un", FALSE
);
4105 register_opcode_emulation (OP_LREM
, "__emul_lrem", "long long long", mono_llrem
, "mono_llrem", FALSE
);
4106 register_opcode_emulation (OP_LREM_UN
, "__emul_lrem_un", "long long long", mono_llrem_un
, "mono_llrem_un", FALSE
);
4108 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4109 register_opcode_emulation (OP_LMUL_OVF_UN
, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un
, "mono_llmult_ovf_un", FALSE
);
4110 register_opcode_emulation (OP_LMUL_OVF
, "__emul_lmul_ovf", "long long long", mono_llmult_ovf
, "mono_llmult_ovf", FALSE
);
4113 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4114 register_opcode_emulation (OP_LSHL
, "__emul_lshl", "long long int32", mono_lshl
, "mono_lshl", TRUE
);
4115 register_opcode_emulation (OP_LSHR
, "__emul_lshr", "long long int32", mono_lshr
, "mono_lshr", TRUE
);
4116 register_opcode_emulation (OP_LSHR_UN
, "__emul_lshr_un", "long long int32", mono_lshr_un
, "mono_lshr_un", TRUE
);
4119 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4120 register_opcode_emulation (OP_IDIV
, "__emul_op_idiv", "int32 int32 int32", mono_idiv
, "mono_idiv", FALSE
);
4121 register_opcode_emulation (OP_IDIV_UN
, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un
, "mono_idiv_un", FALSE
);
4122 register_opcode_emulation (OP_IREM
, "__emul_op_irem", "int32 int32 int32", mono_irem
, "mono_irem", FALSE
);
4123 register_opcode_emulation (OP_IREM_UN
, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un
, "mono_irem_un", FALSE
);
4126 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4127 register_opcode_emulation (OP_IMUL
, "__emul_op_imul", "int32 int32 int32", mono_imul
, "mono_imul", TRUE
);
4130 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4131 register_opcode_emulation (OP_IMUL_OVF
, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf
, "mono_imul_ovf", FALSE
);
4132 register_opcode_emulation (OP_IMUL_OVF_UN
, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un
, "mono_imul_ovf_un", FALSE
);
4135 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4136 register_opcode_emulation (OP_FDIV
, "__emul_fdiv", "double double double", mono_fdiv
, "mono_fdiv", FALSE
);
4139 register_opcode_emulation (OP_FCONV_TO_U8
, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8
, "mono_fconv_u8", FALSE
);
4140 register_opcode_emulation (OP_RCONV_TO_U8
, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8
, "mono_rconv_u8", FALSE
);
4141 register_opcode_emulation (OP_FCONV_TO_U4
, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4
, "mono_fconv_u4", FALSE
);
4142 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8
, "mono_fconv_ovf_i8", FALSE
);
4143 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8
, "mono_fconv_ovf_u8", FALSE
);
4144 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8
, "mono_rconv_ovf_i8", FALSE
);
4145 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8
, "mono_rconv_ovf_u8", FALSE
);
4148 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4149 register_opcode_emulation (OP_FCONV_TO_I8
, "__emul_fconv_to_i8", "long double", mono_fconv_i8
, "mono_fconv_i8", FALSE
);
4150 register_opcode_emulation (OP_RCONV_TO_I8
, "__emul_rconv_to_i8", "long float", mono_rconv_i8
, "mono_rconv_i8", FALSE
);
4153 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4154 register_opcode_emulation (OP_ICONV_TO_R_UN
, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un
, "mono_conv_to_r8_un", FALSE
);
4156 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4157 register_opcode_emulation (OP_LCONV_TO_R8
, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8
, "mono_lconv_to_r8", FALSE
);
4159 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4160 register_opcode_emulation (OP_LCONV_TO_R4
, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4
, "mono_lconv_to_r4", FALSE
);
4162 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4163 register_opcode_emulation (OP_LCONV_TO_R_UN
, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un
, "mono_lconv_to_r8_un", FALSE
);
4165 #ifdef MONO_ARCH_EMULATE_FREM
4166 register_opcode_emulation (OP_FREM
, "__emul_frem", "double double double", fmod
, "fmod", FALSE
);
4167 register_opcode_emulation (OP_RREM
, "__emul_rrem", "float float float", fmodf
, "fmodf", FALSE
);
4170 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4171 if (mono_arch_is_soft_float ()) {
4172 register_opcode_emulation (OP_FSUB
, "__emul_fsub", "double double double", mono_fsub
, "mono_fsub", FALSE
);
4173 register_opcode_emulation (OP_FADD
, "__emul_fadd", "double double double", mono_fadd
, "mono_fadd", FALSE
);
4174 register_opcode_emulation (OP_FMUL
, "__emul_fmul", "double double double", mono_fmul
, "mono_fmul", FALSE
);
4175 register_opcode_emulation (OP_FNEG
, "__emul_fneg", "double double", mono_fneg
, "mono_fneg", FALSE
);
4176 register_opcode_emulation (OP_ICONV_TO_R8
, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8
, "mono_conv_to_r8", FALSE
);
4177 register_opcode_emulation (OP_ICONV_TO_R4
, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4
, "mono_conv_to_r4", FALSE
);
4178 register_opcode_emulation (OP_FCONV_TO_R4
, "__emul_fconv_to_r4", "double double", mono_fconv_r4
, "mono_fconv_r4", FALSE
);
4179 register_opcode_emulation (OP_FCONV_TO_I1
, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1
, "mono_fconv_i1", FALSE
);
4180 register_opcode_emulation (OP_FCONV_TO_I2
, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2
, "mono_fconv_i2", FALSE
);
4181 register_opcode_emulation (OP_FCONV_TO_I4
, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4182 register_opcode_emulation (OP_FCONV_TO_U1
, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1
, "mono_fconv_u1", FALSE
);
4183 register_opcode_emulation (OP_FCONV_TO_U2
, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2
, "mono_fconv_u2", FALSE
);
4185 #if SIZEOF_VOID_P == 4
4186 register_opcode_emulation (OP_FCONV_TO_I
, "__emul_fconv_to_i", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4189 register_opcode_emulation (OP_FBEQ
, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq
, "mono_fcmp_eq", FALSE
);
4190 register_opcode_emulation (OP_FBLT
, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt
, "mono_fcmp_lt", FALSE
);
4191 register_opcode_emulation (OP_FBGT
, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt
, "mono_fcmp_gt", FALSE
);
4192 register_opcode_emulation (OP_FBLE
, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le
, "mono_fcmp_le", FALSE
);
4193 register_opcode_emulation (OP_FBGE
, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge
, "mono_fcmp_ge", FALSE
);
4194 register_opcode_emulation (OP_FBNE_UN
, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un
, "mono_fcmp_ne_un", FALSE
);
4195 register_opcode_emulation (OP_FBLT_UN
, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un
, "mono_fcmp_lt_un", FALSE
);
4196 register_opcode_emulation (OP_FBGT_UN
, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un
, "mono_fcmp_gt_un", FALSE
);
4197 register_opcode_emulation (OP_FBLE_UN
, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un
, "mono_fcmp_le_un", FALSE
);
4198 register_opcode_emulation (OP_FBGE_UN
, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un
, "mono_fcmp_ge_un", FALSE
);
4200 register_opcode_emulation (OP_FCEQ
, "__emul_fcmp_ceq", "uint32 double double", mono_fceq
, "mono_fceq", FALSE
);
4201 register_opcode_emulation (OP_FCGT
, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt
, "mono_fcgt", FALSE
);
4202 register_opcode_emulation (OP_FCGT_UN
, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un
, "mono_fcgt_un", FALSE
);
4203 register_opcode_emulation (OP_FCLT
, "__emul_fcmp_clt", "uint32 double double", mono_fclt
, "mono_fclt", FALSE
);
4204 register_opcode_emulation (OP_FCLT_UN
, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un
, "mono_fclt_un", FALSE
);
4206 register_icall (mono_fload_r4
, "mono_fload_r4", "double ptr", FALSE
);
4207 register_icall (mono_fstore_r4
, "mono_fstore_r4", "void double ptr", FALSE
);
4208 register_icall (mono_fload_r4_arg
, "mono_fload_r4_arg", "uint32 double", FALSE
);
4209 register_icall (mono_isfinite
, "mono_isfinite", "uint32 double", FALSE
);
4212 register_icall (mono_ckfinite
, "mono_ckfinite", "double double", FALSE
);
4214 #ifdef COMPRESSED_INTERFACE_BITMAP
4215 register_icall (mono_class_interface_match
, "mono_class_interface_match", "uint32 ptr int32", TRUE
);
4218 #if SIZEOF_REGISTER == 4
4219 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4
, "mono_fconv_u4", TRUE
);
4221 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "ulong double", mono_fconv_u8
, "mono_fconv_u8", TRUE
);
4224 /* other jit icalls */
4225 register_icall (ves_icall_mono_delegate_ctor
, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE
);
4226 register_icall (mono_class_static_field_address
, "mono_class_static_field_address",
4227 "ptr ptr ptr", FALSE
);
4228 register_icall (mono_ldtoken_wrapper
, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE
);
4229 register_icall (mono_ldtoken_wrapper_generic_shared
, "mono_ldtoken_wrapper_generic_shared",
4230 "ptr ptr ptr ptr", FALSE
);
4231 register_icall (mono_get_special_static_data
, "mono_get_special_static_data", "ptr int", FALSE
);
4232 register_icall (ves_icall_mono_ldstr
, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE
);
4233 register_icall (mono_helper_stelem_ref_check
, "mono_helper_stelem_ref_check", "void object object", FALSE
);
4234 register_icall (ves_icall_object_new
, "ves_icall_object_new", "object ptr ptr", FALSE
);
4235 register_icall (ves_icall_object_new_specific
, "ves_icall_object_new_specific", "object ptr", FALSE
);
4236 register_icall (ves_icall_array_new
, "ves_icall_array_new", "object ptr ptr int32", FALSE
);
4237 register_icall (ves_icall_array_new_specific
, "ves_icall_array_new_specific", "object ptr int32", FALSE
);
4238 register_icall (ves_icall_runtime_class_init
, "ves_icall_runtime_class_init", "void ptr", FALSE
);
4239 register_icall (mono_ldftn
, "mono_ldftn", "ptr ptr", FALSE
);
4240 register_icall (mono_ldvirtfn
, "mono_ldvirtfn", "ptr object ptr", FALSE
);
4241 register_icall (mono_ldvirtfn_gshared
, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE
);
4242 register_icall (mono_helper_compile_generic_method
, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE
);
4243 register_icall (mono_helper_ldstr
, "mono_helper_ldstr", "object ptr int", FALSE
);
4244 register_icall (mono_helper_ldstr_mscorlib
, "mono_helper_ldstr_mscorlib", "object int", FALSE
);
4245 register_icall (mono_helper_newobj_mscorlib
, "mono_helper_newobj_mscorlib", "object int", FALSE
);
4246 register_icall (mono_value_copy
, "mono_value_copy", "void ptr ptr ptr", FALSE
);
4247 register_icall (mono_object_castclass_unbox
, "mono_object_castclass_unbox", "object object ptr", FALSE
);
4248 register_icall (mono_break
, "mono_break", NULL
, TRUE
);
4249 register_icall (mono_create_corlib_exception_0
, "mono_create_corlib_exception_0", "object int", TRUE
);
4250 register_icall (mono_create_corlib_exception_1
, "mono_create_corlib_exception_1", "object int object", TRUE
);
4251 register_icall (mono_create_corlib_exception_2
, "mono_create_corlib_exception_2", "object int object object", TRUE
);
4252 register_icall (mono_array_new_1
, "mono_array_new_1", "object ptr int", FALSE
);
4253 register_icall (mono_array_new_2
, "mono_array_new_2", "object ptr int int", FALSE
);
4254 register_icall (mono_array_new_3
, "mono_array_new_3", "object ptr int int int", FALSE
);
4255 register_icall (mono_array_new_4
, "mono_array_new_4", "object ptr int int int int", FALSE
);
4256 register_icall (mono_get_native_calli_wrapper
, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE
);
4257 register_icall (mono_resume_unwind
, "mono_resume_unwind", "void", TRUE
);
4258 register_icall (mono_gsharedvt_constrained_call
, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE
);
4259 register_icall (mono_gsharedvt_value_copy
, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE
);
4261 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4262 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4264 register_icall (mono_object_castclass_with_cache
, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE
);
4265 register_icall (mono_object_isinst_with_cache
, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE
);
4266 register_icall (mono_generic_class_init
, "mono_generic_class_init", "void ptr", FALSE
);
4267 register_icall (mono_fill_class_rgctx
, "mono_fill_class_rgctx", "ptr ptr int", FALSE
);
4268 register_icall (mono_fill_method_rgctx
, "mono_fill_method_rgctx", "ptr ptr int", FALSE
);
4270 register_icall (mono_debugger_agent_user_break
, "mono_debugger_agent_user_break", "void", FALSE
);
4272 register_icall (mono_aot_init_llvm_method
, "mono_aot_init_llvm_method", "void ptr int", TRUE
);
4273 register_icall (mono_aot_init_gshared_method_this
, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE
);
4274 register_icall (mono_aot_init_gshared_method_mrgctx
, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE
);
4275 register_icall (mono_aot_init_gshared_method_vtable
, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE
);
4277 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt
, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4278 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt
, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4279 register_icall_no_wrapper (mono_resolve_generic_virtual_call
, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4280 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call
, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4281 /* This needs a wrapper so it can have a preserveall cconv */
4282 register_icall (mono_init_vtable_slot
, "mono_init_vtable_slot", "ptr ptr int", FALSE
);
4283 register_icall (mono_llvmonly_init_delegate
, "mono_llvmonly_init_delegate", "void object", TRUE
);
4284 register_icall (mono_llvmonly_init_delegate_virtual
, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE
);
4285 register_icall (mono_get_assembly_object
, "mono_get_assembly_object", "object ptr", TRUE
);
4286 register_icall (mono_get_method_object
, "mono_get_method_object", "object ptr", TRUE
);
4287 register_icall (mono_throw_method_access
, "mono_throw_method_access", "void ptr ptr", FALSE
);
4288 register_icall_no_wrapper (mono_dummy_jit_icall
, "mono_dummy_jit_icall", "void");
4290 register_icall_with_wrapper (mono_monitor_enter_internal
, "mono_monitor_enter_internal", "void obj");
4291 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, "mono_monitor_enter_v4_internal", "void obj ptr");
4292 register_icall_no_wrapper (mono_monitor_enter_fast
, "mono_monitor_enter_fast", "int obj");
4293 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, "mono_monitor_enter_v4_fast", "int obj ptr");
4296 register_icall (pthread_getspecific
, "pthread_getspecific", "ptr ptr", TRUE
);
4298 /* Register tls icalls */
4299 register_icall_no_wrapper (mono_tls_get_thread
, "mono_tls_get_thread", "ptr");
4300 register_icall_no_wrapper (mono_tls_get_jit_tls
, "mono_tls_get_jit_tls", "ptr");
4301 register_icall_no_wrapper (mono_tls_get_domain
, "mono_tls_get_domain", "ptr");
4302 register_icall_no_wrapper (mono_tls_get_sgen_thread_info
, "mono_tls_get_sgen_thread_info", "ptr");
4303 register_icall_no_wrapper (mono_tls_get_lmf_addr
, "mono_tls_get_lmf_addr", "ptr");
4304 register_icall_no_wrapper (mono_tls_set_thread
, "mono_tls_set_thread", "void ptr");
4305 register_icall_no_wrapper (mono_tls_set_jit_tls
, "mono_tls_set_jit_tls", "void ptr");
4306 register_icall_no_wrapper (mono_tls_set_domain
, "mono_tls_set_domain", "void ptr");
4307 register_icall_no_wrapper (mono_tls_set_sgen_thread_info
, "mono_tls_set_sgen_thread_info", "void ptr");
4308 register_icall_no_wrapper (mono_tls_set_lmf_addr
, "mono_tls_set_lmf_addr", "void ptr");
4311 MonoJitStats mono_jit_stats
= {0};
4314 print_jit_stats (void)
4316 if (mono_jit_stats
.enabled
) {
4317 g_print ("Mono Jit statistics\n");
4318 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/100.0,
4319 mono_jit_stats
.max_ratio_method
);
4320 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats
.biggest_method_size
,
4321 mono_jit_stats
.biggest_method
);
4323 g_print ("Delegates created: %ld\n", mono_stats
.delegate_creations
);
4324 g_print ("Initialized classes: %ld\n", mono_stats
.initialized_class_count
);
4325 g_print ("Used classes: %ld\n", mono_stats
.used_class_count
);
4326 g_print ("Generic vtables: %ld\n", mono_stats
.generic_vtable_count
);
4327 g_print ("Methods: %ld\n", mono_stats
.method_count
);
4328 g_print ("Static data size: %ld\n", mono_stats
.class_static_data_size
);
4329 g_print ("VTable data size: %ld\n", mono_stats
.class_vtable_size
);
4330 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4332 g_print ("\nInitialized classes: %ld\n", mono_stats
.generic_class_count
);
4333 g_print ("Inflated types: %ld\n", mono_stats
.inflated_type_count
);
4334 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4336 g_print ("Sharable generic methods: %ld\n", mono_stats
.generics_sharable_methods
);
4337 g_print ("Unsharable generic methods: %ld\n", mono_stats
.generics_unsharable_methods
);
4338 g_print ("Shared generic methods: %ld\n", mono_stats
.generics_shared_methods
);
4339 g_print ("Shared vtype generic methods: %ld\n", mono_stats
.gsharedvt_methods
);
4341 g_print ("IMT tables size: %ld\n", mono_stats
.imt_tables_size
);
4342 g_print ("IMT number of tables: %ld\n", mono_stats
.imt_number_of_tables
);
4343 g_print ("IMT number of methods: %ld\n", mono_stats
.imt_number_of_methods
);
4344 g_print ("IMT used slots: %ld\n", mono_stats
.imt_used_slots
);
4345 g_print ("IMT colliding slots: %ld\n", mono_stats
.imt_slots_with_collisions
);
4346 g_print ("IMT max collisions: %ld\n", mono_stats
.imt_max_collisions_in_slot
);
4347 g_print ("IMT methods at max col: %ld\n", mono_stats
.imt_method_count_when_max_collisions
);
4348 g_print ("IMT trampolines size: %ld\n", mono_stats
.imt_trampolines_size
);
4350 g_print ("JIT info table inserts: %ld\n", mono_stats
.jit_info_table_insert_count
);
4351 g_print ("JIT info table removes: %ld\n", mono_stats
.jit_info_table_remove_count
);
4352 g_print ("JIT info table lookups: %ld\n", mono_stats
.jit_info_table_lookup_count
);
4354 g_free (mono_jit_stats
.max_ratio_method
);
4355 mono_jit_stats
.max_ratio_method
= NULL
;
4356 g_free (mono_jit_stats
.biggest_method
);
4357 mono_jit_stats
.biggest_method
= NULL
;
4362 mini_cleanup (MonoDomain
*domain
)
4364 if (mono_profiler_sampling_enabled ())
4365 mono_runtime_shutdown_stat_profiler ();
4367 MONO_PROFILER_RAISE (runtime_shutdown_begin
, ());
4370 cominterop_release_all_rcws ();
4373 #ifndef MONO_CROSS_COMPILE
4375 * mono_domain_finalize () needs to be called early since it needs the
4376 * execution engine still fully working (it may invoke managed finalizers).
4378 mono_domain_finalize (domain
, 2000);
4381 /* This accesses metadata so needs to be called before runtime shutdown */
4384 #ifndef MONO_CROSS_COMPILE
4385 mono_runtime_cleanup (domain
);
4388 mono_threadpool_cleanup ();
4390 MONO_PROFILER_RAISE (runtime_shutdown_end
, ());
4392 mono_profiler_cleanup ();
4394 if (profile_options
)
4395 g_ptr_array_free (profile_options
, TRUE
);
4397 free_jit_tls_data ((MonoJitTlsData
*)mono_tls_get_jit_tls ());
4399 mono_icall_cleanup ();
4401 mono_runtime_cleanup_handlers ();
4403 #ifndef MONO_CROSS_COMPILE
4404 mono_domain_free (domain
, TRUE
);
4409 mono_llvm_cleanup ();
4412 mono_aot_cleanup ();
4414 mono_trampolines_cleanup ();
4416 mono_unwind_cleanup ();
4418 mono_code_manager_destroy (global_codeman
);
4419 g_free (vtable_trampolines
);
4421 mini_jit_cleanup ();
4423 mono_tramp_info_cleanup ();
4425 mono_arch_cleanup ();
4427 mono_generic_sharing_cleanup ();
4431 mono_trace_cleanup ();
4433 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, stdout
);
4435 if (mono_inject_async_exc_method
)
4436 mono_method_desc_free (mono_inject_async_exc_method
);
4438 mono_tls_free_keys ();
4440 mono_os_mutex_destroy (&jit_mutex
);
4442 mono_code_manager_cleanup ();
4445 mono_w32handle_cleanup ();
4450 mono_set_defaults (int verbose_level
, guint32 opts
)
4452 mini_verbose
= verbose_level
;
4453 mono_set_optimizations (opts
);
4457 mono_disable_optimizations (guint32 opts
)
4459 default_opt
&= ~opts
;
4463 mono_set_optimizations (guint32 opts
)
4466 default_opt_set
= TRUE
;
4467 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4468 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
4471 mono_set_generic_sharing_vt_supported (TRUE
);
4476 mono_set_verbose_level (guint32 level
)
4478 mini_verbose
= level
;
4482 * mono_get_runtime_build_info:
4483 * The returned string is owned by the caller. The returned string
4484 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4485 * \returns the runtime version + build date in string format.
4488 mono_get_runtime_build_info (void)
4490 if (mono_build_date
)
4491 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
4493 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
4497 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
4499 GHashTable
*assemblies
= (GHashTable
*)user_data
;
4500 MonoImage
*image
= mono_assembly_get_image (ass
);
4501 MonoMethod
*method
, *invoke
;
4504 if (g_hash_table_lookup (assemblies
, ass
))
4507 g_hash_table_insert (assemblies
, ass
, ass
);
4509 if (mini_verbose
> 0)
4510 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
4512 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
4515 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, &error
);
4517 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
4520 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
4522 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
4526 if (mini_verbose
> 1) {
4527 char * desc
= mono_method_full_name (method
, TRUE
);
4528 g_print ("Compiling %d %s\n", count
, desc
);
4531 mono_compile_method_checked (method
, &error
);
4532 if (!is_ok (&error
)) {
4533 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
4536 if (strcmp (method
->name
, "Finalize") == 0) {
4537 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4538 mono_compile_method_checked (invoke
, &error
);
4539 mono_error_assert_ok (&error
);
4541 #ifndef DISABLE_REMOTING
4542 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature (method
)->hasthis
) {
4543 invoke
= mono_marshal_get_remoting_invoke_with_check (method
);
4544 mono_compile_method_checked (invoke
, &error
);
4545 mono_error_assert_ok (&error
);
4550 /* Load and precompile referenced assemblies as well */
4551 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
4552 mono_assembly_load_reference (image
, i
);
4553 if (image
->references
[i
])
4554 mono_precompile_assembly (image
->references
[i
], assemblies
);
4558 void mono_precompile_assemblies ()
4560 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
4562 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
4564 g_hash_table_destroy (assemblies
);
4569 * Have to export this for AOT.
4572 mono_personality (void)
4575 g_assert_not_reached ();
4579 static MonoBreakPolicy
4580 always_insert_breakpoint (MonoMethod
*method
)
4582 return MONO_BREAK_POLICY_ALWAYS
;
4585 static MonoBreakPolicyFunc break_policy_func
= always_insert_breakpoint
;
4588 * mono_set_break_policy:
4589 * \param policy_callback the new callback function
4591 * Allow embedders to decide whether to actually obey breakpoint instructions
4592 * (both break IL instructions and \c Debugger.Break method calls), for example
4593 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4594 * untrusted or semi-trusted code.
4596 * \p policy_callback will be called every time a break point instruction needs to
4597 * be inserted with the method argument being the method that calls \c Debugger.Break
4598 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4599 * if it wants the breakpoint to not be effective in the given method.
4600 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4603 mono_set_break_policy (MonoBreakPolicyFunc policy_callback
)
4605 if (policy_callback
)
4606 break_policy_func
= policy_callback
;
4608 break_policy_func
= always_insert_breakpoint
;
4612 mini_should_insert_breakpoint (MonoMethod
*method
)
4614 switch (break_policy_func (method
)) {
4615 case MONO_BREAK_POLICY_ALWAYS
:
4617 case MONO_BREAK_POLICY_NEVER
:
4619 case MONO_BREAK_POLICY_ON_DBG
:
4620 g_warning ("mdb no longer supported");
4623 g_warning ("Incorrect value returned from break policy callback");
4628 // Custom handlers currently only implemented by Windows.
4631 mono_runtime_install_custom_handlers (const char *handlers
)
4637 mono_runtime_install_custom_handlers_usage (void)
4640 "Custom Handlers:\n"
4641 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4642 " separated list of available handlers to install.\n"
4644 "No handlers supported on current platform.\n");
4646 #endif /* HOST_WIN32 */