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-compiler.h>
68 #include <mono/utils/mono-proclib.h>
69 #include <mono/metadata/w32handle.h>
70 #include <mono/metadata/threadpool.h>
73 #include "seq-points.h"
79 #include "aot-compiler.h"
80 #include "aot-runtime.h"
82 #include "jit-icalls.h"
85 #include "mini-llvm.h"
86 #include "debugger-agent.h"
88 #include "mini-runtime.h"
89 #include "interp/interp.h"
91 #ifdef MONO_ARCH_LLVM_SUPPORTED
93 #include "mini-llvm-cpp.h"
98 static guint32 default_opt
= 0;
99 static gboolean default_opt_set
= FALSE
;
101 gboolean mono_compile_aot
= FALSE
;
102 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
103 gboolean mono_aot_only
= FALSE
;
104 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
105 gboolean mono_llvm_only
= FALSE
;
106 MonoAotMode mono_aot_mode
= MONO_AOT_MODE_NONE
;
107 MonoEEFeatures mono_ee_features
;
109 const char *mono_build_date
;
110 gboolean mono_do_signal_chaining
;
111 gboolean mono_do_crash_chaining
;
112 int mini_verbose
= 0;
115 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
116 * it can load AOT code compiled by LLVM.
118 gboolean mono_use_llvm
= FALSE
;
120 gboolean mono_use_interpreter
= FALSE
;
121 const char *mono_interp_opts_string
= NULL
;
123 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
124 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
125 static mono_mutex_t jit_mutex
;
127 static MonoCodeManager
*global_codeman
;
129 MonoDebugOptions mini_debug_options
;
132 #ifdef VALGRIND_JIT_REGISTER_MAP
133 int valgrind_register
;
135 GList
* mono_aot_paths
;
137 static GPtrArray
*profile_options
;
139 static GSList
*tramp_infos
;
140 GSList
*mono_interp_only_classes
;
142 static void register_icalls (void);
145 mono_running_on_valgrind (void)
148 if (RUNNING_ON_VALGRIND
){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register
= TRUE
;
164 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
166 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
169 ud
->method
= (MonoMethod
*)key
;
173 G_GNUC_UNUSED
static char*
174 get_method_from_ip (void *ip
)
180 MonoDomain
*domain
= mono_domain_get ();
181 MonoDebugSourceLocation
*location
;
182 FindTrampUserData user_data
;
185 domain
= mono_get_root_domain ();
187 ji
= mono_jit_info_table_find_internal (domain
, ip
, TRUE
, TRUE
);
190 user_data
.method
= NULL
;
191 mono_domain_lock (domain
);
192 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
193 mono_domain_unlock (domain
);
194 if (user_data
.method
) {
195 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
196 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
202 } else if (ji
->is_trampoline
) {
203 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ((MonoTrampInfo
*)ji
->d
.tramp_info
)->name
);
207 method
= jinfo_get_method (ji
);
208 method_name
= mono_method_full_name (method
, TRUE
);
209 /* FIXME: unused ? */
210 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
212 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
);
214 mono_debug_free_source_location (location
);
215 g_free (method_name
);
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
235 return get_method_from_ip (ip
);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
250 mono_print_method_from_ip (void *ip
)
254 MonoDebugSourceLocation
*source
;
255 MonoDomain
*domain
= mono_domain_get ();
256 MonoDomain
*target_domain
= mono_domain_get ();
257 FindTrampUserData user_data
;
258 MonoGenericSharingContext
*gsctx
;
259 const char *shared_type
;
262 domain
= mono_get_root_domain ();
263 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
264 if (ji
&& ji
->is_trampoline
) {
265 MonoTrampInfo
*tinfo
= (MonoTrampInfo
*)ji
->d
.tramp_info
;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
273 user_data
.method
= NULL
;
274 mono_domain_lock (domain
);
275 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
276 mono_domain_unlock (domain
);
278 if (user_data
.method
) {
279 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
280 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
285 g_print ("No method at %p\n", ip
);
289 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
290 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
292 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
295 if (gsctx
->is_gsharedvt
)
296 shared_type
= "gsharedvt ";
298 shared_type
= "gshared ";
301 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
);
304 g_print ("%s:%d\n", source
->source_file
, source
->row
);
307 mono_debug_free_source_location (source
);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
321 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
331 cmethod
= jinfo_get_method (caller
);
332 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
333 (strstr (cmethod
->name
, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size
)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman
) {
354 /* This can happen during startup */
355 global_codeman
= mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman
, size
);
360 ptr
= mono_code_manager_reserve (global_codeman
, size
);
366 /* The callback shouldn't take any locks */
368 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
371 mono_code_manager_foreach (global_codeman
, func
, user_data
);
376 * mono_create_unwind_op:
378 * Create an unwind op with the given parameters.
381 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
383 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
394 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
396 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
399 res
->has_context
= context
!= NULL
;
401 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
407 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
409 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
413 * mono_tramp_info_create:
415 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
416 * of JI, and UNWIND_OPS.
419 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
421 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
423 info
->name
= g_strdup ((char*)name
);
425 info
->code_size
= code_size
;
427 info
->unwind_ops
= unwind_ops
;
433 mono_tramp_info_free (MonoTrampInfo
*info
)
438 mono_free_unwind_info (info
->unwind_ops
);
439 if (info
->owns_uw_info
)
440 g_free (info
->uw_info
);
445 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
449 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
450 mono_jit_info_init (ji
, NULL
, info
->code
, info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
451 ji
->d
.tramp_info
= info
;
452 ji
->is_trampoline
= TRUE
;
454 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
456 mono_jit_info_table_add (domain
, ji
);
460 * mono_tramp_info_register:
462 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
467 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
475 domain
= mono_get_root_domain ();
478 copy
= mono_domain_alloc0 (domain
, sizeof (MonoTrampInfo
));
480 copy
= g_new0 (MonoTrampInfo
, 1);
482 copy
->code
= info
->code
;
483 copy
->code_size
= info
->code_size
;
484 copy
->name
= g_strdup (info
->name
);
486 if (info
->unwind_ops
) {
487 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
488 copy
->owns_uw_info
= TRUE
;
490 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
491 guint8
*temp
= copy
->uw_info
;
492 copy
->uw_info
= mono_domain_alloc (domain
, copy
->uw_info_len
);
493 memcpy (copy
->uw_info
, temp
, copy
->uw_info_len
);
497 /* Trampolines from aot have the unwind ops already encoded */
498 copy
->uw_info
= info
->uw_info
;
499 copy
->uw_info_len
= info
->uw_info_len
;
502 mono_save_trampoline_xdebug_info (info
);
503 mono_lldb_save_trampoline_info (info
);
505 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
507 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
511 /* If no root domain has been created yet, postpone the registration. */
513 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
515 } else if (copy
->uw_info
) {
516 /* Only register trampolines that have unwind infos */
517 register_trampoline_jit_info (domain
, copy
);
520 if (mono_jit_map_is_enabled ())
521 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
523 mono_tramp_info_free (info
);
527 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
529 mono_tramp_info_register_internal (info
, domain
, FALSE
);
533 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
535 mono_tramp_info_register_internal (info
, domain
, TRUE
);
539 mono_tramp_info_cleanup (void)
543 for (l
= tramp_infos
; l
; l
= l
->next
) {
544 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
546 mono_tramp_info_free (info
);
548 g_slist_free (tramp_infos
);
551 /* Register trampolines created before the root domain was created in the jit info tables */
553 register_trampolines (MonoDomain
*domain
)
557 for (l
= tramp_infos
; l
; l
= l
->next
) {
558 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
560 register_trampoline_jit_info (domain
, info
);
564 G_GNUC_UNUSED
static void
570 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
571 * Set a breakpoint in break_count () to break the last time <x> is done.
573 G_GNUC_UNUSED gboolean
574 mono_debug_count (void)
576 static int count
= 0, int_val
= 0;
577 static gboolean inited
, has_value
= FALSE
;
582 char *value
= g_getenv ("COUNT");
584 int_val
= atoi (value
);
594 if (count
== int_val
)
604 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
609 gconstpointer trampoline
;
610 MonoDomain
*domain
= mono_get_root_domain ();
611 gboolean check_exc
= TRUE
;
613 if (callinfo
->wrapper
)
614 return callinfo
->wrapper
;
616 if (callinfo
->trampoline
)
617 return callinfo
->trampoline
;
619 if (!strcmp (callinfo
->name
, "mono_thread_interruption_checkpoint"))
620 /* This icall is used to check for exceptions, so don't check in the wrapper */
623 name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
624 wrapper
= mono_marshal_get_icall_wrapper (callinfo
->sig
, name
, callinfo
->func
, check_exc
);
628 trampoline
= mono_compile_method_checked (wrapper
, error
);
629 mono_error_assert_ok (error
);
632 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, error
);
633 mono_error_assert_ok (error
);
634 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
638 if (!callinfo
->trampoline
) {
639 mono_register_jit_icall_wrapper (callinfo
, trampoline
);
640 callinfo
->trampoline
= trampoline
;
642 mono_loader_unlock ();
644 return callinfo
->trampoline
;
648 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
650 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
653 static MonoJitDynamicMethodInfo
*
654 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
656 MonoJitDynamicMethodInfo
*res
;
658 if (domain_jit_info (domain
)->dynamic_code_hash
)
659 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
666 register_opcode_emulation (int opcode
, const char *name
, const char *sigstr
, gpointer func
, const char *symbol
, gboolean no_wrapper
)
669 mini_register_opcode_emulation (opcode
, name
, sigstr
, func
, symbol
, no_wrapper
);
671 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
673 g_assert (!sig
->hasthis
);
674 g_assert (sig
->param_count
< 3);
676 mono_register_jit_icall_full (func
, name
, sig
, no_wrapper
, symbol
);
681 * For JIT icalls implemented in C.
682 * NAME should be the same as the name of the C function whose address is FUNC.
683 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
684 * can't throw exceptions.
687 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean avoid_wrapper
)
689 MonoMethodSignature
*sig
;
692 sig
= mono_create_icall_signature (sigstr
);
696 mono_register_jit_icall_full (func
, name
, sig
, avoid_wrapper
, avoid_wrapper
? name
: NULL
);
700 register_icall_no_wrapper (gpointer func
, const char *name
, const char *sigstr
)
702 MonoMethodSignature
*sig
;
705 sig
= mono_create_icall_signature (sigstr
);
709 mono_register_jit_icall_full (func
, name
, sig
, TRUE
, name
);
713 register_icall_with_wrapper (gpointer func
, const char *name
, const char *sigstr
)
715 MonoMethodSignature
*sig
;
718 sig
= mono_create_icall_signature (sigstr
);
722 mono_register_jit_icall_full (func
, name
, sig
, FALSE
, NULL
);
726 register_dyn_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
728 MonoMethodSignature
*sig
;
731 sig
= mono_create_icall_signature (sigstr
);
735 mono_register_jit_icall (func
, name
, sig
, save
);
741 MonoJitTlsData
*jit_tls
;
743 if ((jit_tls
= mono_tls_get_jit_tls ()))
746 * We do not assert here because this function can be called from
747 * mini-gc.c on a thread that has not executed any managed code, yet
748 * (the thread object allocation can trigger a collection).
754 mono_get_lmf_addr (void)
756 return (MonoLMF
**)mono_tls_get_lmf_addr ();
760 mono_set_lmf (MonoLMF
*lmf
)
762 (*mono_get_lmf_addr ()) = lmf
;
766 mono_get_jit_tls (void)
768 return (MonoJitTlsData
*)mono_tls_get_jit_tls ();
772 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
774 MonoThreadInfo
*info
;
776 mono_tls_set_jit_tls (jit_tls
);
778 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
779 info
= mono_thread_info_current ();
781 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
785 mono_set_lmf_addr (gpointer lmf_addr
)
787 MonoThreadInfo
*info
;
789 mono_tls_set_lmf_addr (lmf_addr
);
791 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
792 info
= mono_thread_info_current ();
794 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
800 * Push an MonoLMFExt frame on the LMF stack.
803 mono_push_lmf (MonoLMFExt
*ext
)
807 lmf_addr
= mono_get_lmf_addr ();
809 ext
->lmf
.previous_lmf
= *lmf_addr
;
810 /* Mark that this is a MonoLMFExt */
811 ext
->lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
->lmf
.previous_lmf
) | 2);
813 mono_set_lmf ((MonoLMF
*)ext
);
819 * Pop the last frame from the LMF stack.
822 mono_pop_lmf (MonoLMF
*lmf
)
824 mono_set_lmf ((MonoLMF
*)(((gssize
)lmf
->previous_lmf
) & ~3));
828 * mono_jit_thread_attach:
830 * Called by Xamarin.Mac and other products. Attach thread to runtime if
831 * needed and switch to @domain.
833 * @return the original domain which needs to be restored, or NULL.
836 mono_jit_thread_attach (MonoDomain
*domain
)
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
) ||
893 ((obj
->vtable
->klass
) == mono_class_get_appdomain_unloaded_exception_class () &&
894 mono_thread_info_current ()->runtime_thread
)) {
897 mono_invoke_unhandled_exception_hook (obj
);
902 setup_jit_tls_data (gpointer stack_start
, gpointer abort_func
)
904 MonoJitTlsData
*jit_tls
;
907 jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
911 jit_tls
= g_new0 (MonoJitTlsData
, 1);
913 jit_tls
->abort_func
= (void (*)(MonoObject
*))abort_func
;
914 jit_tls
->end_of_stack
= stack_start
;
916 mono_set_jit_tls (jit_tls
);
918 lmf
= g_new0 (MonoLMF
, 1);
919 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
921 jit_tls
->first_lmf
= lmf
;
923 mono_set_lmf_addr (&jit_tls
->lmf
);
927 #ifdef MONO_ARCH_HAVE_TLS_INIT
928 mono_arch_tls_init ();
931 mono_setup_altstack (jit_tls
);
937 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
939 mono_arch_free_jit_tls_data (jit_tls
);
940 mono_free_altstack (jit_tls
);
942 g_free (jit_tls
->first_lmf
);
943 g_free (jit_tls
->interp_context
);
948 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
950 MonoThreadInfo
*thread
;
951 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
952 thread
= mono_thread_info_current_unchecked ();
954 thread
->jit_data
= jit_tls
;
956 mono_arch_cpu_init ();
959 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
962 mono_thread_abort_dummy (MonoObject
*obj
)
964 if (mono_thread_attach_aborted_cb
)
965 mono_thread_attach_aborted_cb (obj
);
967 mono_thread_abort (obj
);
971 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
973 MonoThreadInfo
*thread
;
974 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
975 thread
= mono_thread_info_current_unchecked ();
977 thread
->jit_data
= jit_tls
;
979 mono_arch_cpu_init ();
983 mini_thread_cleanup (MonoNativeThreadId tid
)
985 MonoJitTlsData
*jit_tls
= NULL
;
986 MonoThreadInfo
*info
;
988 info
= mono_thread_info_current_unchecked ();
990 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
991 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
992 * not a trivial thing.
994 * The current offender is mono_thread_manage which cleanup threads from the outside.
996 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
997 jit_tls
= (MonoJitTlsData
*)info
->jit_data
;
998 info
->jit_data
= NULL
;
1000 mono_set_jit_tls (NULL
);
1002 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1003 if (mono_get_lmf ()) {
1004 mono_set_lmf (NULL
);
1005 mono_set_lmf_addr (NULL
);
1008 info
= mono_thread_info_lookup (tid
);
1010 jit_tls
= (MonoJitTlsData
*)info
->jit_data
;
1011 info
->jit_data
= NULL
;
1013 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1017 free_jit_tls_data (jit_tls
);
1021 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
1023 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
1027 ji
->data
.target
= target
;
1033 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1035 static const char* const patch_info_str
[] = {
1036 #define PATCH_INFO(a,b) "" #a,
1037 #include "patch-info.h"
1042 mono_ji_type_to_string (MonoJumpInfoType type
)
1044 return patch_info_str
[type
];
1048 mono_print_ji (const MonoJumpInfo
*ji
)
1051 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1052 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1054 printf ("[RGCTX_FETCH ");
1055 mono_print_ji (entry
->data
);
1056 printf (" - %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1059 case MONO_PATCH_INFO_METHODCONST
: {
1060 char *s
= mono_method_full_name (ji
->data
.method
, TRUE
);
1061 printf ("[METHODCONST - %s]", s
);
1065 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
1066 printf ("[INTERNAL_METHOD - %s]", ji
->data
.name
);
1070 printf ("[%s]", patch_info_str
[ji
->type
]);
1078 mono_ji_type_to_string (MonoJumpInfoType type
)
1084 mono_print_ji (const MonoJumpInfo
*ji
)
1091 * mono_patch_info_dup_mp:
1093 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1096 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1098 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1099 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1101 switch (patch_info
->type
) {
1102 case MONO_PATCH_INFO_RVA
:
1103 case MONO_PATCH_INFO_LDSTR
:
1104 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1105 case MONO_PATCH_INFO_LDTOKEN
:
1106 case MONO_PATCH_INFO_DECLSEC
:
1107 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1108 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1110 case MONO_PATCH_INFO_SWITCH
:
1111 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1112 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1113 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1114 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1116 case MONO_PATCH_INFO_RGCTX_FETCH
:
1117 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1118 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1119 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1120 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1122 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1123 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1124 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1126 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1127 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1128 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1130 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1131 MonoGSharedVtMethodInfo
*info
;
1132 MonoGSharedVtMethodInfo
*oinfo
;
1135 oinfo
= patch_info
->data
.gsharedvt_method
;
1136 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1137 res
->data
.gsharedvt_method
= info
;
1138 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1139 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1140 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1141 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1142 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1144 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1146 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1147 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1150 case MONO_PATCH_INFO_VIRT_METHOD
: {
1151 MonoJumpInfoVirtMethod
*info
;
1152 MonoJumpInfoVirtMethod
*oinfo
;
1154 oinfo
= patch_info
->data
.virt_method
;
1155 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1156 res
->data
.virt_method
= info
;
1157 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1168 mono_patch_info_hash (gconstpointer data
)
1170 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1173 case MONO_PATCH_INFO_RVA
:
1174 case MONO_PATCH_INFO_LDSTR
:
1175 case MONO_PATCH_INFO_LDTOKEN
:
1176 case MONO_PATCH_INFO_DECLSEC
:
1177 return (ji
->type
<< 8) | ji
->data
.token
->token
;
1178 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1179 return (ji
->type
<< 8) | ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1180 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1181 return (ji
->type
<< 8) | g_str_hash (ji
->data
.name
);
1182 case MONO_PATCH_INFO_VTABLE
:
1183 case MONO_PATCH_INFO_CLASS
:
1184 case MONO_PATCH_INFO_IID
:
1185 case MONO_PATCH_INFO_ADJUSTED_IID
:
1186 case MONO_PATCH_INFO_METHODCONST
:
1187 case MONO_PATCH_INFO_METHOD
:
1188 case MONO_PATCH_INFO_METHOD_JUMP
:
1189 case MONO_PATCH_INFO_IMAGE
:
1190 case MONO_PATCH_INFO_ICALL_ADDR
:
1191 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1192 case MONO_PATCH_INFO_FIELD
:
1193 case MONO_PATCH_INFO_SFLDA
:
1194 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1195 case MONO_PATCH_INFO_METHOD_RGCTX
:
1196 case MONO_PATCH_INFO_SIGNATURE
:
1197 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1198 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1199 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1200 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1201 return (ji
->type
<< 8) | (gssize
)ji
->data
.target
;
1202 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1203 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt
->method
;
1204 case MONO_PATCH_INFO_RGCTX_FETCH
:
1205 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1206 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1208 return (ji
->type
<< 8) | (gssize
)e
->method
| (e
->in_mrgctx
) | e
->info_type
| mono_patch_info_hash (e
->data
);
1210 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1211 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1212 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1213 case MONO_PATCH_INFO_GC_NURSERY_START
:
1214 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1215 case MONO_PATCH_INFO_GOT_OFFSET
:
1216 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1217 case MONO_PATCH_INFO_AOT_MODULE
:
1218 case MONO_PATCH_INFO_JIT_THREAD_ATTACH
:
1219 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
:
1220 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
:
1221 return (ji
->type
<< 8);
1222 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1223 return (ji
->type
<< 8) | (ji
->data
.index
);
1224 case MONO_PATCH_INFO_SWITCH
:
1225 return (ji
->type
<< 8) | ji
->data
.table
->table_size
;
1226 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1227 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt_method
->method
;
1228 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1229 /* Hash on the selector name */
1230 return g_str_hash (ji
->data
.target
);
1231 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1232 return (ji
->type
<< 8) | (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1233 case MONO_PATCH_INFO_LDSTR_LIT
:
1234 return g_str_hash (ji
->data
.target
);
1235 case MONO_PATCH_INFO_VIRT_METHOD
: {
1236 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1238 return (ji
->type
<< 8) | (gssize
)info
->klass
| (gssize
)info
->method
;
1240 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1241 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1242 return (ji
->type
<< 8) | g_str_hash (ji
->data
.target
);
1243 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1244 return (ji
->type
<< 8) | mono_signature_hash (ji
->data
.sig
);
1246 printf ("info type: %d\n", ji
->type
);
1247 mono_print_ji (ji
); printf ("\n");
1248 g_assert_not_reached ();
1254 * mono_patch_info_equal:
1256 * This might fail to recognize equivalent patches, i.e. floats, so its only
1257 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1261 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1263 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1264 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1266 if (ji1
->type
!= ji2
->type
)
1269 switch (ji1
->type
) {
1270 case MONO_PATCH_INFO_RVA
:
1271 case MONO_PATCH_INFO_LDSTR
:
1272 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1273 case MONO_PATCH_INFO_LDTOKEN
:
1274 case MONO_PATCH_INFO_DECLSEC
:
1275 if ((ji1
->data
.token
->image
!= ji2
->data
.token
->image
) ||
1276 (ji1
->data
.token
->token
!= ji2
->data
.token
->token
) ||
1277 (ji1
->data
.token
->has_context
!= ji2
->data
.token
->has_context
) ||
1278 (ji1
->data
.token
->context
.class_inst
!= ji2
->data
.token
->context
.class_inst
) ||
1279 (ji1
->data
.token
->context
.method_inst
!= ji2
->data
.token
->context
.method_inst
))
1282 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1283 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1284 case MONO_PATCH_INFO_RGCTX_FETCH
:
1285 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1286 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1287 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1289 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
);
1291 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1292 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1293 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1295 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1297 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1298 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1299 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1300 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
;
1301 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1302 return ji1
->data
.index
== ji2
->data
.index
;
1303 case MONO_PATCH_INFO_VIRT_METHOD
:
1304 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1305 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1306 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1307 if (ji1
->data
.target
== ji2
->data
.target
)
1309 return strcmp (ji1
->data
.target
, ji2
->data
.target
) == 0 ? 1 : 0;
1310 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1311 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
) ? 1 : 0;
1313 if (ji1
->data
.target
!= ji2
->data
.target
)
1322 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1324 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1325 gconstpointer target
= NULL
;
1329 switch (patch_info
->type
) {
1330 case MONO_PATCH_INFO_BB
:
1332 * FIXME: This could be hit for methods without a prolog. Should use -1
1333 * but too much code depends on a 0 initial value.
1335 //g_assert (patch_info->data.bb->native_offset);
1336 target
= patch_info
->data
.bb
->native_offset
+ code
;
1338 case MONO_PATCH_INFO_ABS
:
1339 target
= patch_info
->data
.target
;
1341 case MONO_PATCH_INFO_LABEL
:
1342 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1344 case MONO_PATCH_INFO_IP
:
1347 case MONO_PATCH_INFO_METHOD_REL
:
1348 target
= code
+ patch_info
->data
.offset
;
1350 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
1351 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1353 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info
->data
.name
);
1354 g_assert_not_reached ();
1356 target
= mono_icall_get_wrapper (mi
);
1359 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1360 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
: {
1361 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1363 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info
->data
.name
);
1364 g_assert_not_reached ();
1369 case MONO_PATCH_INFO_METHOD_JUMP
:
1370 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1371 if (!mono_error_ok (error
))
1374 case MONO_PATCH_INFO_METHOD
:
1375 if (patch_info
->data
.method
== method
) {
1378 /* get the trampoline to the method from the domain */
1379 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1380 if (!mono_error_ok (error
))
1384 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1387 mono_domain_lock (domain
);
1388 if (!domain_jit_info (domain
)->method_code_hash
)
1389 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1390 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1392 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1393 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1395 mono_domain_unlock (domain
);
1399 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1400 g_assert (mono_threads_are_safepoints_enabled ());
1401 target
= (gpointer
)&mono_polling_required
;
1403 case MONO_PATCH_INFO_SWITCH
: {
1404 gpointer
*jump_table
;
1406 if (method
&& method
->dynamic
) {
1407 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1409 if (mono_aot_only
) {
1410 jump_table
= (void **)mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1412 jump_table
= (void **)mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1416 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1417 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1420 target
= jump_table
;
1423 case MONO_PATCH_INFO_METHODCONST
:
1424 case MONO_PATCH_INFO_CLASS
:
1425 case MONO_PATCH_INFO_IMAGE
:
1426 case MONO_PATCH_INFO_FIELD
:
1427 case MONO_PATCH_INFO_SIGNATURE
:
1428 case MONO_PATCH_INFO_AOT_MODULE
:
1429 target
= patch_info
->data
.target
;
1431 case MONO_PATCH_INFO_IID
:
1432 mono_class_init (patch_info
->data
.klass
);
1433 target
= GUINT_TO_POINTER (m_class_get_interface_id (patch_info
->data
.klass
));
1435 case MONO_PATCH_INFO_ADJUSTED_IID
:
1436 mono_class_init (patch_info
->data
.klass
);
1437 target
= GUINT_TO_POINTER ((guint32
)(-((m_class_get_interface_id (patch_info
->data
.klass
) + 1) * SIZEOF_VOID_P
)));
1439 case MONO_PATCH_INFO_VTABLE
:
1440 target
= mono_class_vtable_checked (domain
, patch_info
->data
.klass
, error
);
1441 mono_error_assert_ok (error
);
1443 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1444 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1446 if (del_tramp
->is_virtual
)
1447 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1449 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1452 case MONO_PATCH_INFO_SFLDA
: {
1453 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, patch_info
->data
.field
->parent
, error
);
1454 mono_error_assert_ok (error
);
1456 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1457 gpointer addr
= NULL
;
1459 mono_domain_lock (domain
);
1460 if (domain
->special_static_fields
)
1461 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1462 mono_domain_unlock (domain
);
1467 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (method
&& mono_class_needs_cctor_run (vtable
->klass
, method
)))
1468 /* Done by the generated code */
1472 if (!mono_runtime_class_init_full (vtable
, error
)) {
1477 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1480 case MONO_PATCH_INFO_RVA
: {
1481 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1484 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1485 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1488 case MONO_PATCH_INFO_R4
:
1489 case MONO_PATCH_INFO_R8
:
1490 target
= patch_info
->data
.target
;
1492 case MONO_PATCH_INFO_EXC_NAME
:
1493 target
= patch_info
->data
.name
;
1495 case MONO_PATCH_INFO_LDSTR
:
1497 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1498 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1500 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1502 MonoClass
*handle_class
;
1504 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1505 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1506 if (!mono_error_ok (error
))
1508 mono_class_init (handle_class
);
1509 mono_class_init (mono_class_from_mono_type ((MonoType
*)handle
));
1511 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1512 if (!mono_error_ok (error
))
1516 case MONO_PATCH_INFO_LDTOKEN
: {
1518 MonoClass
*handle_class
;
1520 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1521 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1522 mono_error_assert_msg_ok (error
, "Could not patch ldtoken");
1523 mono_class_init (handle_class
);
1528 case MONO_PATCH_INFO_DECLSEC
:
1529 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1531 case MONO_PATCH_INFO_ICALL_ADDR
:
1532 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1533 /* run_cctors == 0 -> AOT */
1534 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1535 const char *exc_class
;
1536 const char *exc_arg
;
1539 target
= mono_lookup_pinvoke_call (patch_info
->data
.method
, &exc_class
, &exc_arg
);
1541 if (mono_aot_only
) {
1542 mono_error_set_exception_instance (error
, mono_exception_from_name_msg (mono_defaults
.corlib
, "System", exc_class
, exc_arg
));
1545 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
));
1551 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1553 if (!target
&& run_cctors
)
1554 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1557 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1558 target
= mono_thread_interruption_request_flag ();
1560 case MONO_PATCH_INFO_METHOD_RGCTX
:
1561 target
= mini_method_get_rgctx (patch_info
->data
.method
);
1563 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1564 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1566 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1569 case MONO_PATCH_INFO_BB_OVF
:
1570 case MONO_PATCH_INFO_EXC_OVF
:
1571 case MONO_PATCH_INFO_GOT_OFFSET
:
1572 case MONO_PATCH_INFO_NONE
:
1574 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1575 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1577 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1580 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1581 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1583 /* AOT, not needed */
1586 target
= mono_arch_get_seq_point_info (domain
, code
);
1589 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1590 int card_table_shift_bits
;
1591 gpointer card_table_mask
;
1593 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1596 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1600 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1603 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1607 mono_gc_get_nursery (&shift_bits
, &size
);
1609 target
= (gpointer
)(mgreg_t
)shift_bits
;
1612 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1613 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1616 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1620 case MONO_PATCH_INFO_LDSTR_LIT
: {
1624 len
= strlen ((const char *)patch_info
->data
.target
);
1625 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1626 memcpy (s
, patch_info
->data
.target
, len
);
1631 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1632 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1634 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1635 target
= mono_tls_get_tls_getter (patch_info
->data
.index
, FALSE
);
1637 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1638 target
= mono_tls_get_tls_setter (patch_info
->data
.index
, FALSE
);
1640 case MONO_PATCH_INFO_JIT_THREAD_ATTACH
: {
1641 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1646 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
: {
1647 target
= (gpointer
) &mono_profiler_state
.gc_allocation_count
;
1650 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
: {
1651 target
= (gpointer
) &mono_profiler_state
.exception_clause_count
;
1655 g_assert_not_reached ();
1658 return (gpointer
)target
;
1662 * mini_register_jump_site:
1664 * Register IP as a jump/tailcall site which calls METHOD.
1665 * This is needed because common_call_trampoline () cannot patch
1666 * the call site because the caller ip is not available for jumps.
1669 mini_register_jump_site (MonoDomain
*domain
, MonoMethod
*method
, gpointer ip
)
1671 MonoJumpList
*jlist
;
1673 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1674 method
= shared_method
? shared_method
: method
;
1676 mono_domain_lock (domain
);
1677 jlist
= (MonoJumpList
*)g_hash_table_lookup (domain_jit_info (domain
)->jump_target_hash
, method
);
1679 jlist
= (MonoJumpList
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpList
));
1680 g_hash_table_insert (domain_jit_info (domain
)->jump_target_hash
, method
, jlist
);
1682 jlist
->list
= g_slist_prepend (jlist
->list
, ip
);
1683 mono_domain_unlock (domain
);
1687 * mini_patch_jump_sites:
1689 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1692 mini_patch_jump_sites (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1694 GHashTable
*hash
= domain_jit_info (domain
)->jump_target_hash
;
1699 MonoJumpInfo patch_info
;
1700 MonoJumpList
*jlist
;
1703 /* The caller/callee might use different instantiations */
1704 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1705 method
= shared_method
? shared_method
: method
;
1707 mono_domain_lock (domain
);
1708 jlist
= (MonoJumpList
*)g_hash_table_lookup (hash
, method
);
1710 g_hash_table_remove (hash
, method
);
1711 mono_domain_unlock (domain
);
1713 patch_info
.next
= NULL
;
1714 patch_info
.ip
.i
= 0;
1715 patch_info
.type
= MONO_PATCH_INFO_METHOD_JUMP
;
1716 patch_info
.data
.method
= method
;
1718 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1719 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
)
1720 mono_arch_patch_code_new (NULL
, domain
, (guint8
*)tmp
->data
, &patch_info
, addr
);
1722 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1723 // for gshared methods
1724 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
1726 mono_arch_patch_code (NULL
, NULL
, domain
, tmp
->data
, &patch_info
, TRUE
, error
);
1727 mono_error_assert_ok (error
);
1734 mini_init_gsctx (MonoDomain
*domain
, MonoMemPool
*mp
, MonoGenericContext
*context
, MonoGenericSharingContext
*gsctx
)
1736 MonoGenericInst
*inst
;
1739 memset (gsctx
, 0, sizeof (MonoGenericSharingContext
));
1741 if (context
&& context
->class_inst
) {
1742 inst
= context
->class_inst
;
1743 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1744 MonoType
*type
= inst
->type_argv
[i
];
1746 if (mini_is_gsharedvt_gparam (type
))
1747 gsctx
->is_gsharedvt
= TRUE
;
1750 if (context
&& context
->method_inst
) {
1751 inst
= context
->method_inst
;
1753 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1754 MonoType
*type
= inst
->type_argv
[i
];
1756 if (mini_is_gsharedvt_gparam (type
))
1757 gsctx
->is_gsharedvt
= TRUE
;
1763 * LOCKING: Acquires the jit code hash lock.
1766 mini_lookup_method (MonoDomain
*domain
, MonoMethod
*method
, MonoMethod
*shared
)
1769 static gboolean inited
= FALSE
;
1770 static int lookups
= 0;
1771 static int failed_lookups
= 0;
1773 mono_domain_jit_code_hash_lock (domain
);
1774 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
1775 if (!ji
&& shared
) {
1776 /* Try generic sharing */
1777 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, shared
);
1778 if (ji
&& !ji
->has_generic_jit_info
)
1781 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &lookups
);
1782 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &failed_lookups
);
1790 mono_domain_jit_code_hash_unlock (domain
);
1796 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
1802 ji
= mini_lookup_method (domain
, method
, NULL
);
1805 if (!mono_method_is_generic_sharable (method
, FALSE
))
1807 shared
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
1808 mono_error_assert_ok (error
);
1809 ji
= mini_lookup_method (domain
, method
, shared
);
1816 mini_get_class (MonoMethod
*method
, guint32 token
, MonoGenericContext
*context
)
1821 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1822 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
1824 klass
= mono_class_inflate_generic_class_checked (klass
, context
, error
);
1825 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1828 klass
= mono_class_get_and_inflate_typespec_checked (m_class_get_image (method
->klass
), token
, context
, error
);
1829 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1832 mono_class_init (klass
);
1837 static FILE* perf_map_file
;
1840 mono_enable_jit_map (void)
1842 if (!perf_map_file
) {
1844 g_snprintf (name
, sizeof (name
), "/tmp/perf-%d.map", getpid ());
1846 perf_map_file
= fopen (name
, "w");
1851 mono_emit_jit_tramp (void *start
, int size
, const char *desc
)
1854 fprintf (perf_map_file
, "%llx %x %s\n", (long long unsigned int)(gsize
)start
, size
, desc
);
1858 mono_emit_jit_map (MonoJitInfo
*jinfo
)
1860 if (perf_map_file
) {
1861 char *name
= mono_method_full_name (jinfo_get_method (jinfo
), TRUE
);
1862 mono_emit_jit_tramp (jinfo
->code_start
, jinfo
->code_size
, name
);
1868 mono_jit_map_is_enabled (void)
1870 return perf_map_file
!= NULL
;
1876 no_gsharedvt_in_wrapper (void)
1878 g_assert_not_reached ();
1884 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.
1885 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1886 Dependency management in this case is too complex to justify implementing it.
1888 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1891 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1892 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1893 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1894 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1899 int compilation_count
; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1900 int ref_count
; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1901 int threads_waiting
; /* Number of threads waiting on this job */
1902 gboolean has_cond
; /* True if @cond was initialized */
1903 gboolean done
; /* True if the method finished JIT'ing */
1904 MonoCoopCond cond
; /* Cond sleeping threads wait one */
1905 } JitCompilationEntry
;
1908 GPtrArray
*in_flight_methods
; //JitCompilationEntry*
1910 } JitCompilationData
;
1913 Timeout, in millisecounds, that we wait other threads to finish JITing.
1914 This value can't be too small or we won't see enough methods being reused and it can't be too big to cause massive stalls due to unforseable circunstances.
1916 #define MAX_JIT_TIMEOUT_MS 1000
1919 static JitCompilationData compilation_data
;
1920 static int jit_methods_waited
, jit_methods_multiple
, jit_methods_overload
, jit_spurious_wakeups_or_timeouts
;
1923 mini_jit_init_job_control (void)
1925 mono_coop_mutex_init (&compilation_data
.lock
);
1926 compilation_data
.in_flight_methods
= g_ptr_array_new ();
1930 lock_compilation_data (void)
1932 mono_coop_mutex_lock (&compilation_data
.lock
);
1936 unlock_compilation_data (void)
1938 mono_coop_mutex_unlock (&compilation_data
.lock
);
1941 static JitCompilationEntry
*
1942 find_method (MonoMethod
*method
, MonoDomain
*domain
)
1945 for (i
= 0; i
< compilation_data
.in_flight_methods
->len
; ++i
){
1946 JitCompilationEntry
*e
= compilation_data
.in_flight_methods
->pdata
[i
];
1947 if (e
->method
== method
&& e
->domain
== domain
)
1955 add_current_thread (MonoJitTlsData
*jit_tls
)
1957 ++jit_tls
->active_jit_methods
;
1961 unref_jit_entry (JitCompilationEntry
*entry
)
1964 if (entry
->ref_count
)
1966 if (entry
->has_cond
)
1967 mono_coop_cond_destroy (&entry
->cond
);
1972 * Returns true if this method waited successfully for another thread to JIT it
1975 wait_or_register_method_to_compile (MonoMethod
*method
, MonoDomain
*domain
)
1977 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1978 JitCompilationEntry
*entry
;
1980 static gboolean inited
;
1982 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_waited
);
1983 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_multiple
);
1984 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_overload
);
1985 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_spurious_wakeups_or_timeouts
);
1989 lock_compilation_data ();
1991 if (!(entry
= find_method (method
, domain
))) {
1992 entry
= g_new0 (JitCompilationEntry
, 1);
1993 entry
->method
= method
;
1994 entry
->domain
= domain
;
1995 entry
->compilation_count
= entry
->ref_count
= 1;
1996 g_ptr_array_add (compilation_data
.in_flight_methods
, entry
);
1997 g_assert (find_method (method
, domain
) == entry
);
1998 add_current_thread (jit_tls
);
2000 unlock_compilation_data ();
2002 } else if (jit_tls
->active_jit_methods
> 0 || mono_threads_is_current_thread_in_protected_block ()) {
2003 //We can't suspend the current thread if it's already JITing a method.
2004 //Dependency management is too compilated and we want to get rid of this anyways.
2006 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2007 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2009 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2010 ++entry
->compilation_count
;
2011 ++jit_methods_multiple
;
2012 ++jit_tls
->active_jit_methods
;
2014 unlock_compilation_data ();
2017 ++jit_methods_waited
;
2020 if (!entry
->has_cond
) {
2021 mono_coop_cond_init (&entry
->cond
);
2022 entry
->has_cond
= TRUE
;
2026 ++entry
->threads_waiting
;
2028 g_assert (entry
->has_cond
);
2029 mono_coop_cond_timedwait (&entry
->cond
, &compilation_data
.lock
, MAX_JIT_TIMEOUT_MS
);
2030 --entry
->threads_waiting
;
2033 unref_jit_entry (entry
);
2034 unlock_compilation_data ();
2037 //We hit the timeout or a spurious wakeup, fallback to JITing
2038 g_assert (entry
->ref_count
> 1);
2039 unref_jit_entry (entry
);
2040 ++jit_spurious_wakeups_or_timeouts
;
2042 ++entry
->compilation_count
;
2043 ++jit_methods_multiple
;
2044 ++jit_tls
->active_jit_methods
;
2046 unlock_compilation_data ();
2054 unregister_method_for_compile (MonoMethod
*method
, MonoDomain
*target_domain
)
2056 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
2058 lock_compilation_data ();
2060 g_assert (jit_tls
->active_jit_methods
> 0);
2061 --jit_tls
->active_jit_methods
;
2063 JitCompilationEntry
*entry
= find_method (method
, target_domain
);
2064 g_assert (entry
); // It would be weird to fail
2067 if (entry
->threads_waiting
) {
2068 g_assert (entry
->has_cond
);
2069 mono_coop_cond_broadcast (&entry
->cond
);
2072 if (--entry
->compilation_count
== 0) {
2073 g_ptr_array_remove (compilation_data
.in_flight_methods
, entry
);
2074 unref_jit_entry (entry
);
2077 unlock_compilation_data ();
2081 create_jit_info_for_trampoline (MonoMethod
*wrapper
, MonoTrampInfo
*info
)
2083 MonoDomain
*domain
= mono_get_root_domain ();
2088 if (info
->uw_info
) {
2089 uw_info
= info
->uw_info
;
2090 info_len
= info
->uw_info_len
;
2092 uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, &info_len
);
2095 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
);
2096 jinfo
->d
.method
= wrapper
;
2097 jinfo
->code_start
= info
->code
;
2098 jinfo
->code_size
= info
->code_size
;
2099 jinfo
->unwind_info
= mono_cache_unwind_info (uw_info
, info_len
);
2108 compile_special (MonoMethod
*method
, MonoDomain
*target_domain
, MonoError
*error
)
2113 if (mono_llvm_only
) {
2114 if (method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2115 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2117 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
) {
2119 * These wrappers are only created for signatures which are in the program, but
2120 * sometimes we load methods too eagerly and have to create them even if they
2121 * will never be called.
2123 return no_gsharedvt_in_wrapper
;
2128 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
2129 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
2131 MonoMethodPInvoke
* piinfo
= (MonoMethodPInvoke
*) method
;
2133 if (!piinfo
->addr
) {
2134 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
2135 piinfo
->addr
= mono_lookup_internal_call (method
);
2136 else if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
2138 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method
, TRUE
), m_class_get_image (method
->klass
)->name
);
2140 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method
, TRUE
), m_class_get_image (method
->klass
)->name
);
2143 mono_lookup_pinvoke_call (method
, NULL
, NULL
);
2145 nm
= mono_marshal_get_native_wrapper (method
, TRUE
, mono_aot_only
);
2146 gpointer compiled_method
= mono_jit_compile_method_jit_only (nm
, error
);
2147 return_val_if_nok (error
, NULL
);
2148 code
= mono_get_addr_from_ftnptr (compiled_method
);
2149 jinfo
= mono_jit_info_table_find (target_domain
, code
);
2151 jinfo
= mono_jit_info_table_find (mono_domain_get (), code
);
2153 MONO_PROFILER_RAISE (jit_done
, (method
, jinfo
));
2155 } else if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
2156 const char *name
= method
->name
;
2160 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2161 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
2162 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2165 * We need to make sure this wrapper
2166 * is compiled because it might end up
2167 * in an (M)RGCTX if generic sharing
2168 * is enabled, and would be called
2169 * indirectly. If it were a
2170 * trampoline we'd try to patch that
2171 * indirect call, which is not
2174 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper_full (mi
, TRUE
));
2175 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2176 if (mono_llvm_only
) {
2177 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
2178 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2179 return_val_if_nok (error
, NULL
);
2180 return mono_get_addr_from_ftnptr (compiled_ptr
);
2183 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2184 if (mono_use_interpreter
)
2187 return mono_create_delegate_trampoline (target_domain
, method
->klass
);
2188 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
2189 nm
= mono_marshal_get_delegate_begin_invoke (method
);
2190 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2191 return_val_if_nok (error
, NULL
);
2192 return mono_get_addr_from_ftnptr (compiled_ptr
);
2193 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
2194 nm
= mono_marshal_get_delegate_end_invoke (method
);
2195 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2196 return_val_if_nok (error
, NULL
);
2197 return mono_get_addr_from_ftnptr (compiled_ptr
);
2201 full_name
= mono_method_full_name (method
, TRUE
);
2202 mono_error_set_invalid_program (error
, "Unrecognizable runtime implemented method '%s'", full_name
);
2207 if (method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2208 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2210 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
|| info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_OUT
) {
2211 static MonoTrampInfo
*in_tinfo
, *out_tinfo
;
2212 MonoTrampInfo
*tinfo
;
2214 gboolean is_in
= info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
;
2216 if (is_in
&& in_tinfo
)
2217 return in_tinfo
->code
;
2218 else if (!is_in
&& out_tinfo
)
2219 return out_tinfo
->code
;
2222 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2224 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2226 if (mono_ee_features
.use_aot_trampolines
)
2227 mono_aot_get_trampoline_full (is_in
? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo
);
2229 mono_arch_get_gsharedvt_trampoline (&tinfo
, FALSE
);
2230 jinfo
= create_jit_info_for_trampoline (method
, tinfo
);
2231 mono_jit_info_table_add (mono_get_root_domain (), jinfo
);
2244 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
2246 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
2248 gpointer code
= NULL
, p
;
2250 MonoJitICallInfo
*callinfo
= NULL
;
2251 WrapperInfo
*winfo
= NULL
;
2252 gboolean use_interp
= FALSE
;
2256 if (mono_ee_features
.force_use_interpreter
&& !jit_only
)
2258 if (!use_interp
&& mono_interp_only_classes
) {
2259 for (GSList
*l
= mono_interp_only_classes
; l
; l
= l
->next
) {
2260 if (!strcmp (m_class_get_name (method
->klass
), (char*)l
->data
))
2265 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, error
);
2271 /* Should be handled by the caller */
2272 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
2275 * ICALL wrappers are handled specially, since there is only one copy of them
2276 * shared by all appdomains.
2278 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2279 winfo
= mono_marshal_get_wrapper_info (method
);
2280 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
2281 callinfo
= mono_find_jit_icall_by_addr (winfo
->d
.icall
.func
);
2282 g_assert (callinfo
);
2284 /* Must be domain neutral since there is only one copy */
2285 opt
|= MONO_OPT_SHARED
;
2287 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2288 opt
&= ~MONO_OPT_SHARED
;
2291 if (opt
& MONO_OPT_SHARED
)
2292 target_domain
= mono_get_root_domain ();
2294 target_domain
= domain
;
2296 if (method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2297 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2300 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
2301 MonoGenericContext
*ctx
= NULL
;
2302 if (method
->is_inflated
)
2303 ctx
= mono_method_get_context (method
);
2304 method
= info
->d
.synchronized_inner
.method
;
2306 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2307 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
2313 info
= lookup_method (target_domain
, method
);
2315 /* We can't use a domain specific method in another domain */
2316 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2319 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2320 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2324 if (!mono_runtime_class_init_full (vtable
, error
))
2326 return mono_create_ftnptr (target_domain
, info
->code_start
);
2330 #ifdef MONO_USE_AOT_COMPILER
2331 if (opt
& MONO_OPT_AOT
) {
2332 MonoDomain
*domain
= NULL
;
2334 if (mono_aot_mode
== MONO_AOT_MODE_INTERP
&& method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
2335 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2337 if (info
->subtype
== WRAPPER_SUBTYPE_INTERP_IN
|| info
->subtype
== WRAPPER_SUBTYPE_INTERP_LMF
)
2338 /* AOT'd wrappers for interp must be owned by root domain */
2339 domain
= mono_get_root_domain ();
2343 domain
= mono_domain_get ();
2345 mono_class_init (method
->klass
);
2347 if ((code
= mono_aot_get_method (domain
, method
, error
))) {
2350 if (mono_gc_is_critical_method (method
)) {
2352 * The suspend code needs to be able to lookup these methods by ip in async context,
2353 * so preload their jit info.
2355 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, code
);
2360 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2361 * This is not a problem, since it will be initialized when the method is first
2362 * called by init_method ().
2364 if (!mono_llvm_only
&& !mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2365 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2366 mono_error_assert_ok (error
);
2367 if (!mono_runtime_class_init_full (vtable
, error
))
2377 code
= compile_special (method
, target_domain
, error
);
2379 if (!jit_only
&& !code
&& mono_aot_only
&& mono_use_interpreter
&& method
->wrapper_type
!= MONO_WRAPPER_UNKNOWN
)
2380 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, error
);
2383 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2384 mono_error_set_invalid_operation (error
, "Could not execute the method because the containing type is not fully instantiated.");
2388 if (mono_aot_only
) {
2389 char *fullname
= mono_method_full_name (method
, TRUE
);
2390 mono_error_set_execution_engine (error
, "Attempting to JIT compile method '%s' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.\n", fullname
);
2396 if (wait_or_register_method_to_compile (method
, target_domain
))
2398 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2399 unregister_method_for_compile (method
, target_domain
);
2401 if (!mono_error_ok (error
))
2404 if (!code
&& mono_llvm_only
) {
2405 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2406 g_assert_not_reached ();
2412 if (method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
) {
2416 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2418 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2422 p
= mono_create_ftnptr (target_domain
, code
);
2425 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2426 mono_loader_lock ();
2428 if (!callinfo
->wrapper
) {
2429 callinfo
->wrapper
= p
;
2430 mono_register_jit_icall_wrapper (callinfo
, p
);
2433 mono_loader_unlock ();
2440 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2444 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2449 * mono_jit_compile_method_jit_only:
2451 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2454 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2458 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2462 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2464 invalidated_delegate_trampoline (char *desc
)
2466 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2467 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2473 * mono_jit_free_method:
2475 * Free all memory allocated by the JIT for METHOD.
2478 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2480 MonoJitDynamicMethodInfo
*ji
;
2481 gboolean destroy
= TRUE
;
2482 GHashTableIter iter
;
2483 MonoJumpList
*jlist
;
2484 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2486 g_assert (method
->dynamic
);
2488 if (mono_use_interpreter
) {
2489 mono_domain_jit_code_hash_lock (domain
);
2490 /* InterpMethod is allocated in the domain mempool */
2491 if (mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
2492 mono_internal_hash_table_remove (&info
->interp_code_hash
, method
);
2493 mono_domain_jit_code_hash_unlock (domain
);
2496 mono_domain_lock (domain
);
2497 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2498 mono_domain_unlock (domain
);
2503 mono_debug_remove_method (method
, domain
);
2504 mono_lldb_remove_method (domain
, method
, ji
);
2506 mono_domain_lock (domain
);
2507 g_hash_table_remove (info
->dynamic_code_hash
, method
);
2508 mono_domain_jit_code_hash_lock (domain
);
2509 mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2510 mono_domain_jit_code_hash_unlock (domain
);
2511 g_hash_table_remove (info
->jump_trampoline_hash
, method
);
2512 g_hash_table_remove (info
->seq_points
, method
);
2514 /* requires the domain lock - took above */
2515 mono_conc_hashtable_remove (info
->runtime_invoke_hash
, method
);
2517 /* Remove jump targets in this method */
2518 g_hash_table_iter_init (&iter
, info
->jump_target_hash
);
2519 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2520 GSList
*tmp
, *remove
;
2523 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2524 guint8
*ip
= (guint8
*)tmp
->data
;
2526 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2527 remove
= g_slist_prepend (remove
, tmp
);
2529 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2530 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2532 g_slist_free (remove
);
2534 mono_domain_unlock (domain
);
2536 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2537 if (mini_debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2539 * Instead of freeing the code, change it to call an error routine
2540 * so people can fix their code.
2542 char *type
= mono_type_full_name (m_class_get_byval_arg (method
->klass
));
2543 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2546 mono_arch_invalidate_method (ji
->ji
, invalidated_delegate_trampoline
, type_and_method
);
2552 * This needs to be done before freeing code_mp, since the code address is the
2553 * key in the table, so if we free the code_mp first, another thread can grab the
2554 * same code address and replace our entry in the table.
2556 mono_jit_info_table_remove (domain
, ji
->ji
);
2559 mono_code_manager_destroy (ji
->code_mp
);
2564 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2566 MonoDomain
*target_domain
;
2569 if (default_opt
& MONO_OPT_SHARED
)
2570 target_domain
= mono_get_root_domain ();
2572 target_domain
= domain
;
2574 info
= lookup_method (target_domain
, method
);
2576 /* We can't use a domain specific method in another domain */
2577 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2578 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2581 return info
->code_start
;
2590 static guint32 bisect_opt
= 0;
2591 static GHashTable
*bisect_methods_hash
= NULL
;
2594 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2597 char method_name
[2048];
2600 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2601 g_assert (bisect_methods_hash
);
2603 file
= fopen (method_list_filename
, "r");
2606 while (fgets (method_name
, sizeof (method_name
), file
)) {
2607 size_t len
= strlen (method_name
);
2609 g_assert (method_name
[len
- 1] == '\n');
2610 method_name
[len
- 1] = 0;
2611 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2613 g_assert (feof (file
));
2616 gboolean mono_do_single_method_regression
= FALSE
;
2617 guint32 mono_single_method_regression_opt
= 0;
2618 MonoMethod
*mono_current_single_method
;
2619 GSList
*mono_single_method_list
;
2620 GHashTable
*mono_single_method_hash
;
2623 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 default_opt
)
2627 if (bisect_methods_hash
) {
2628 char *name
= mono_method_full_name (method
, TRUE
);
2629 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2632 return default_opt
| bisect_opt
;
2634 if (!mono_do_single_method_regression
)
2636 if (!mono_current_single_method
) {
2637 if (!mono_single_method_hash
)
2638 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2639 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2640 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2641 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2645 if (method
== mono_current_single_method
)
2646 return mono_single_method_regression_opt
;
2651 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2653 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
2658 gpointer compiled_method
;
2659 gpointer runtime_invoke
;
2661 MonoDynCallInfo
*dyn_call_info
;
2662 MonoClass
*ret_box_class
;
2663 MonoMethodSignature
*sig
;
2664 gboolean gsharedvt_invoke
;
2665 gboolean use_interp
;
2666 gpointer
*wrapper_arg
;
2667 } RuntimeInvokeInfo
;
2669 static RuntimeInvokeInfo
*
2670 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, gboolean use_interp
, MonoError
*error
)
2673 RuntimeInvokeInfo
*info
;
2675 info
= g_new0 (RuntimeInvokeInfo
, 1);
2676 info
->compiled_method
= compiled_method
;
2677 info
->use_interp
= use_interp
;
2678 if (mono_llvm_only
&& method
->string_ctor
)
2679 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
2681 info
->sig
= mono_method_signature (method
);
2683 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
2684 info
->vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2685 if (!mono_error_ok (error
))
2687 g_assert (info
->vtable
);
2689 MonoMethodSignature
*sig
= info
->sig
;
2693 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2694 * in full-aot mode, so we use a slower, but more generic wrapper if
2695 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2697 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2698 if (!mono_llvm_only
&& (mono_aot_only
|| mini_debug_options
.dyn_runtime_invoke
)) {
2699 gboolean supported
= TRUE
;
2702 if (method
->string_ctor
)
2703 sig
= mono_marshal_get_string_ctor_signature (method
);
2705 for (i
= 0; i
< sig
->param_count
; ++i
) {
2706 MonoType
*t
= sig
->params
[i
];
2708 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
2712 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
2716 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
2717 if (mini_debug_options
.dyn_runtime_invoke
)
2718 g_assert (info
->dyn_call_info
);
2723 ret_type
= sig
->ret
;
2724 switch (ret_type
->type
) {
2725 case MONO_TYPE_VOID
:
2737 case MONO_TYPE_BOOLEAN
:
2738 case MONO_TYPE_CHAR
:
2741 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2744 info
->ret_box_class
= mono_defaults
.int_class
;
2746 case MONO_TYPE_STRING
:
2747 case MONO_TYPE_CLASS
:
2748 case MONO_TYPE_ARRAY
:
2749 case MONO_TYPE_SZARRAY
:
2750 case MONO_TYPE_OBJECT
:
2752 case MONO_TYPE_GENERICINST
:
2753 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
2754 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2756 case MONO_TYPE_VALUETYPE
:
2757 info
->ret_box_class
= mono_class_from_mono_type (ret_type
);
2760 g_assert_not_reached ();
2764 if (info
->use_interp
)
2767 if (!info
->dyn_call_info
) {
2768 if (mono_llvm_only
) {
2769 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2770 g_assert_not_reached ();
2772 info
->gsharedvt_invoke
= TRUE
;
2773 if (!callee_gsharedvt
) {
2774 /* Invoke a gsharedvt out wrapper instead */
2775 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2776 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2778 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
2779 info
->wrapper_arg
[0] = mini_add_method_wrappers_llvmonly (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
2781 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2782 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2783 g_free (wrapper_sig
);
2785 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
2786 if (!mono_error_ok (error
)) {
2791 /* Gsharedvt methods can be invoked the same way */
2792 /* The out wrapper has the same signature as the compiled gsharedvt method */
2793 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2795 info
->wrapper_arg
= mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
;
2797 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2798 g_free (wrapper_sig
);
2801 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
2802 if (!mono_error_ok (error
)) {
2812 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2814 MonoMethodSignature
*sig
= info
->sig
;
2815 MonoDomain
*domain
= mono_domain_get ();
2816 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2818 gpointer retval_ptr
;
2819 guint8 retval
[256];
2820 gpointer
*param_refs
;
2825 g_assert (info
->gsharedvt_invoke
);
2828 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2829 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2830 * signatures, so we only have to generate runtime invoke wrappers for these
2832 * This code also handles invocation of gsharedvt methods directly, no
2833 * out wrappers are used in that case.
2835 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2836 param_refs
= (gpointer
*)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2839 * The runtime invoke wrappers expects pointers to primitive types, so have to
2843 args
[pindex
++] = &obj
;
2844 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
2845 retval_ptr
= (gpointer
)&retval
;
2846 args
[pindex
++] = &retval_ptr
;
2848 for (i
= 0; i
< sig
->param_count
; ++i
) {
2849 MonoType
*t
= sig
->params
[i
];
2851 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
2852 MonoClass
*klass
= mono_class_from_mono_type (t
);
2853 guint8
*nullable_buf
;
2856 size
= mono_class_value_size (klass
, NULL
);
2857 nullable_buf
= g_alloca (size
);
2858 g_assert (nullable_buf
);
2860 /* The argument pointed to by params [i] is either a boxed vtype or null */
2861 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
2862 params
[i
] = nullable_buf
;
2865 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
2866 param_refs
[i
] = params
[i
];
2867 params
[i
] = &(param_refs
[i
]);
2869 args
[pindex
++] = ¶ms
[i
];
2871 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2872 args
[pindex
++] = &info
->wrapper_arg
;
2874 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2876 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
2880 if (sig
->ret
->type
!= MONO_TYPE_VOID
&& info
->ret_box_class
)
2881 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2883 return *(MonoObject
**)retval
;
2887 * mono_jit_runtime_invoke:
2888 * \param method: the method to invoke
2889 * \param obj: this pointer
2890 * \param params: array of parameter values.
2891 * \param exc: Set to the exception raised in the managed method.
2892 * \param error: error or caught exception object
2893 * If \p exc is NULL, \p error is thrown instead.
2894 * If coop is enabled, \p exc argument is ignored -
2895 * all exceptions are caught and propagated through \p error
2898 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2900 MonoMethod
*invoke
, *callee
;
2901 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2902 MonoDomain
*domain
= mono_domain_get ();
2903 MonoJitDomainInfo
*domain_info
;
2904 RuntimeInvokeInfo
*info
, *info2
;
2905 MonoJitInfo
*ji
= NULL
;
2906 gboolean callee_gsharedvt
= FALSE
;
2908 if (mono_ee_features
.force_use_interpreter
)
2909 return mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
2915 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
2916 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2920 domain_info
= domain_jit_info (domain
);
2922 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
2925 if (mono_security_core_clr_enabled ()) {
2927 * This might be redundant since mono_class_vtable () already does this,
2928 * but keep it just in case for moonlight.
2930 mono_class_setup_vtable (method
->klass
);
2931 if (mono_class_has_failure (method
->klass
)) {
2932 mono_error_set_for_class_failure (error
, method
->klass
);
2934 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
2939 gpointer compiled_method
;
2942 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2943 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2945 * Array Get/Set/Address methods. The JIT implements them using inline code
2946 * inside the runtime invoke wrappers, so no need to compile them.
2948 if (mono_aot_only
) {
2950 * Call a wrapper, since the runtime invoke wrapper was not generated.
2952 MonoMethod
*wrapper
;
2954 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
2955 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
2962 gboolean use_interp
= FALSE
;
2965 compiled_method
= mono_jit_compile_method_jit_only (callee
, error
);
2966 if (!compiled_method
) {
2967 g_assert (!mono_error_ok (error
));
2969 if (mono_use_interpreter
)
2974 if (mono_llvm_only
) {
2975 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
2976 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2977 if (callee_gsharedvt
)
2978 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji
)));
2981 if (!callee_gsharedvt
)
2982 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
2985 compiled_method
= NULL
;
2988 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, use_interp
, error
);
2989 if (!mono_error_ok (error
))
2992 mono_domain_lock (domain
);
2993 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
2994 mono_domain_unlock (domain
);
3002 * We need this here because mono_marshal_get_runtime_invoke can place
3003 * the helper method in System.Object and not the target class.
3005 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
3007 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3011 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3012 we always catch the exception and propagate it through the MonoError */
3013 gboolean catchExcInMonoError
=
3014 (exc
== NULL
) && mono_threads_are_safepoints_enabled ();
3015 MonoObject
*invoke_exc
= NULL
;
3016 if (catchExcInMonoError
)
3019 /* The wrappers expect this to be initialized to NULL */
3023 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3024 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
= NULL
;
3025 if (info
->dyn_call_info
) {
3026 if (!dyn_runtime_invoke
) {
3027 mono_domain_lock (domain
);
3029 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
3030 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method_jit_only (invoke
, error
);
3031 if (!dyn_runtime_invoke
&& mono_use_interpreter
) {
3032 info
->use_interp
= TRUE
;
3033 info
->dyn_call_info
= NULL
;
3034 } else if (!mono_error_ok (error
)) {
3035 mono_domain_unlock (domain
);
3038 mono_domain_unlock (domain
);
3041 if (info
->dyn_call_info
) {
3042 MonoMethodSignature
*sig
= mono_method_signature (method
);
3044 int i
, pindex
, buf_size
;
3046 guint8 retval
[256];
3048 /* Convert the arguments to the format expected by start_dyn_call () */
3049 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
3052 args
[pindex
++] = &obj
;
3053 for (i
= 0; i
< sig
->param_count
; ++i
) {
3054 MonoType
*t
= sig
->params
[i
];
3057 args
[pindex
++] = ¶ms
[i
];
3058 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
3059 args
[pindex
++] = ¶ms
[i
];
3061 args
[pindex
++] = params
[i
];
3065 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3067 buf_size
= mono_arch_dyn_call_get_buf_size (info
->dyn_call_info
);
3068 buf
= g_alloca (buf_size
);
3071 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
);
3073 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
3074 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
3076 if (catchExcInMonoError
&& *exc
!= NULL
) {
3077 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3081 if (info
->ret_box_class
)
3082 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3084 return *(MonoObject
**)retval
;
3088 if (info
->use_interp
) {
3090 return mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3095 if (mono_llvm_only
) {
3096 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
3100 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3102 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
3104 if (catchExcInMonoError
&& *exc
!= NULL
)
3105 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3114 typedef gpointer (*IMTTrampFunc
) (gpointer
*arg
, MonoMethod
*imt_method
);
3117 * mini_llvmonly_initial_imt_tramp:
3119 * This function is called the first time a call is made through an IMT trampoline.
3120 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
3123 mini_llvmonly_initial_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
3125 IMTTrampInfo
*info
= (IMTTrampInfo
*)arg
;
3130 mono_vtable_build_imt_slot (info
->vtable
, info
->slot
);
3132 imt
= (gpointer
*)info
->vtable
;
3133 imt
-= MONO_IMT_SIZE
;
3135 /* Return what the real IMT trampoline returns */
3136 ftndesc
= imt
[info
->slot
];
3139 if (func
== (IMTTrampFunc
)mini_llvmonly_initial_imt_tramp
)
3140 /* Happens when the imt slot contains only a generic virtual method */
3142 return func ((gpointer
*)ftndesc
[1], imt_method
);
3145 /* This is called indirectly through an imt slot. */
3147 mono_llvmonly_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
3151 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
3152 while (arg
[i
] && arg
[i
] != imt_method
)
3159 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
3161 mono_llvmonly_imt_tramp_1 (gpointer
*arg
, MonoMethod
*imt_method
)
3163 //g_assert (arg [0] == imt_method);
3168 mono_llvmonly_imt_tramp_2 (gpointer
*arg
, MonoMethod
*imt_method
)
3170 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
3171 if (arg
[0] == imt_method
)
3178 mono_llvmonly_imt_tramp_3 (gpointer
*arg
, MonoMethod
*imt_method
)
3180 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
3181 if (arg
[0] == imt_method
)
3183 else if (arg
[2] == imt_method
)
3190 * A version of the imt trampoline used for generic virtual/variant iface methods.
3191 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
3192 * in the search table. The original JIT code had a 'fallback' trampoline it could
3193 * call, but we can't do that, so we just return NULL, and the compiled code
3197 mono_llvmonly_fallback_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
3201 while (arg
[i
] && arg
[i
] != imt_method
)
3210 mono_llvmonly_get_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
, gpointer fail_tramp
)
3214 int i
, index
, real_count
;
3215 gboolean virtual_generic
= FALSE
;
3218 * Create an array which is passed to the imt trampoline functions.
3219 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
3223 for (i
= 0; i
< count
; ++i
) {
3224 MonoIMTCheckItem
*item
= imt_entries
[i
];
3226 if (item
->is_equals
)
3228 if (item
->has_target_code
)
3229 virtual_generic
= TRUE
;
3233 * Initialize all vtable entries reachable from this imt slot, so the compiled
3234 * code doesn't have to check it.
3236 for (i
= 0; i
< count
; ++i
) {
3237 MonoIMTCheckItem
*item
= imt_entries
[i
];
3240 if (!item
->is_equals
|| item
->has_target_code
)
3242 vt_slot
= item
->value
.vtable_slot
;
3243 mono_init_vtable_slot (vtable
, vt_slot
);
3246 /* Save the entries into an array */
3247 buf
= (void **)mono_domain_alloc (domain
, (real_count
+ 1) * 2 * sizeof (gpointer
));
3249 for (i
= 0; i
< count
; ++i
) {
3250 MonoIMTCheckItem
*item
= imt_entries
[i
];
3252 if (!item
->is_equals
)
3255 g_assert (item
->key
);
3256 buf
[(index
* 2)] = item
->key
;
3257 if (item
->has_target_code
)
3258 buf
[(index
* 2) + 1] = item
->value
.target_code
;
3260 buf
[(index
* 2) + 1] = vtable
->vtable
[item
->value
.vtable_slot
];
3263 buf
[(index
* 2)] = NULL
;
3264 buf
[(index
* 2) + 1] = fail_tramp
;
3267 * Return a function descriptor for a C function with 'buf' as its argument.
3268 * It will by called by JITted code.
3270 res
= (void **)mono_domain_alloc (domain
, 2 * sizeof (gpointer
));
3271 switch (real_count
) {
3273 res
[0] = mono_llvmonly_imt_tramp_1
;
3276 res
[0] = mono_llvmonly_imt_tramp_2
;
3279 res
[0] = mono_llvmonly_imt_tramp_3
;
3282 res
[0] = mono_llvmonly_imt_tramp
;
3285 if (virtual_generic
|| fail_tramp
)
3286 res
[0] = mono_llvmonly_fallback_imt_tramp
;
3292 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
3294 MonoException
*exc
= NULL
;
3296 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3297 MONO_SIG_HANDLER_GET_CONTEXT
;
3299 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3301 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3303 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3304 if (mono_arch_is_int_overflow (ctx
, info
))
3306 * The spec says this throws ArithmeticException, but MS throws the derived
3307 * OverflowException.
3309 exc
= mono_get_exception_overflow ();
3311 exc
= mono_get_exception_divide_by_zero ();
3313 exc
= mono_get_exception_divide_by_zero ();
3317 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3320 mono_handle_native_crash ("SIGFPE", ctx
, info
);
3321 if (mono_do_crash_chaining
) {
3322 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3327 mono_arch_handle_exception (ctx
, exc
);
3330 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3333 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler
)
3335 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3336 MONO_SIG_HANDLER_GET_CONTEXT
;
3338 if (mono_runtime_get_no_exec ())
3342 mono_handle_native_crash ("SIGILL", ctx
, info
);
3343 if (mono_do_crash_chaining
) {
3344 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3348 g_assert_not_reached ();
3351 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3352 #define HAVE_SIG_INFO
3355 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3358 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
3359 gpointer fault_addr
= NULL
;
3360 #ifdef HAVE_SIG_INFO
3361 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3365 MONO_SIG_HANDLER_GET_CONTEXT
;
3367 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3368 if (mono_arch_is_single_step_event (info
, ctx
)) {
3369 mini_get_dbg_callbacks ()->single_step_event (ctx
);
3371 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3372 mini_get_dbg_callbacks ()->breakpoint_hit (ctx
);
3377 #if defined(HAVE_SIG_INFO)
3378 #if !defined(HOST_WIN32)
3379 fault_addr
= info
->si_addr
;
3380 if (mono_aot_is_pagefault (info
->si_addr
)) {
3381 mono_aot_handle_pagefault (info
->si_addr
);
3386 /* The thread might no be registered with the runtime */
3387 if (!mono_domain_get () || !jit_tls
) {
3388 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3390 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3391 if (mono_do_crash_chaining
) {
3392 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3398 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3400 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3401 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3404 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3405 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3406 fault_addr
= info
->si_addr
;
3407 if (fault_addr
== NULL
) {
3410 mono_sigctx_to_monoctx (ctx
, &mctx
);
3412 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3416 if (jit_tls
->stack_size
&&
3417 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3419 * The hard-guard page has been hit: there is not much we can do anymore
3420 * Print a hopefully clear message and abort.
3422 mono_handle_hard_stack_ovf (jit_tls
, ji
, ctx
, (guint8
*)info
->si_addr
);
3423 g_assert_not_reached ();
3425 /* The original handler might not like that it is executed on an altstack... */
3426 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3429 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3434 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3437 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3439 if (mono_do_crash_chaining
) {
3440 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3445 mono_arch_handle_exception (ctx
, NULL
);
3449 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3452 MONO_SIG_HANDLER_GET_CONTEXT
;
3454 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3456 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3458 mono_arch_handle_exception (ctx
, exc
);
3460 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3463 #ifndef DISABLE_REMOTING
3464 /* mono_jit_create_remoting_trampoline:
3465 * @method: pointer to the method info
3467 * Creates a trampoline which calls the remoting functions. This
3468 * is used in the vtable of transparent proxies.
3470 * Returns: a pointer to the newly created code
3473 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3476 guint8
*addr
= NULL
;
3480 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature (method
)->generic_param_count
) {
3481 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3485 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3486 (mono_method_signature (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3487 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
, error
);
3490 return_val_if_nok (error
, NULL
);
3491 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3492 return_val_if_nok (error
, NULL
);
3493 return mono_get_addr_from_ftnptr (addr
);
3497 static G_GNUC_UNUSED
void
3498 no_imt_trampoline (void)
3500 g_assert_not_reached ();
3503 static G_GNUC_UNUSED
void
3504 no_vcall_trampoline (void)
3506 g_assert_not_reached ();
3509 static gpointer
*vtable_trampolines
;
3510 static int vtable_trampolines_size
;
3513 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3515 int index
= slot_index
+ MONO_IMT_SIZE
;
3517 if (mono_llvm_only
) {
3518 if (slot_index
< 0) {
3519 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3520 // FIXME: Memory management
3521 gpointer
*ftndesc
= g_malloc (2 * sizeof (gpointer
));
3522 IMTTrampInfo
*info
= g_new0 (IMTTrampInfo
, 1);
3525 ftndesc
[0] = mini_llvmonly_initial_imt_tramp
;
3527 mono_memory_barrier ();
3534 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3535 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3537 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3541 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3542 while (new_size
<= index
)
3544 new_table
= g_new0 (gpointer
, new_size
);
3546 if (vtable_trampolines
)
3547 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3548 g_free (vtable_trampolines
);
3549 mono_memory_barrier ();
3550 vtable_trampolines
= (void **)new_table
;
3551 vtable_trampolines_size
= new_size
;
3556 if (!vtable_trampolines
[index
])
3557 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3558 return vtable_trampolines
[index
];
3562 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3564 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3568 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3573 gpointer
*imt
= (gpointer
*)vt
;
3574 imt
-= MONO_IMT_SIZE
;
3576 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3580 is_callee_gsharedvt_variable (gpointer addr
)
3583 gboolean callee_gsharedvt
;
3585 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
3587 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3588 if (callee_gsharedvt
)
3589 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji
)));
3590 return callee_gsharedvt
;
3594 mini_get_delegate_arg (MonoMethod
*method
, gpointer method_ptr
)
3596 gpointer arg
= NULL
;
3598 if (mono_method_needs_static_rgctx_invoke (method
, FALSE
))
3599 arg
= mini_method_get_rgctx (method
);
3602 * Avoid adding gsharedvt in wrappers since they might not exist if
3603 * this delegate is called through a gsharedvt delegate invoke wrapper.
3604 * Instead, encode that the method is gsharedvt in del->extra_arg,
3605 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3607 if (method
->is_inflated
&& is_callee_gsharedvt_variable (method_ptr
)) {
3608 g_assert ((((mgreg_t
)arg
) & 1) == 0);
3609 arg
= (gpointer
)(((mgreg_t
)arg
) | 1);
3615 mini_init_delegate (MonoDelegate
*del
)
3617 if (mono_use_interpreter
)
3618 mini_get_interp_callbacks ()->init_delegate (del
);
3619 else if (mono_llvm_only
)
3620 del
->extra_arg
= mini_get_delegate_arg (del
->method
, del
->method_ptr
);
3624 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3628 abs_offset
= offset
;
3630 abs_offset
= - abs_offset
;
3631 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ SIZEOF_VOID_P
);
3635 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3637 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3640 static guint8
**cache
= NULL
;
3641 static int cache_size
= 0;
3646 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3649 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3650 is_interface
= mono_class_is_interface (method
->klass
);
3651 load_imt_reg
= is_virtual_generic
|| is_interface
;
3654 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * SIZEOF_VOID_P
;
3656 offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (SIZEOF_VOID_P
));
3658 idx
= (offset
/ SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3659 g_assert (idx
>= 0);
3661 /* Resize the cache to idx + 1 */
3662 if (cache_size
< idx
+ 1) {
3664 if (cache_size
< idx
+ 1) {
3666 int new_cache_size
= idx
+ 1;
3668 new_cache
= g_new0 (guint8
*, new_cache_size
);
3670 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3673 mono_memory_barrier ();
3675 cache_size
= new_cache_size
;
3683 /* FIXME Support more cases */
3684 if (mono_ee_features
.use_aot_trampolines
) {
3685 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3686 g_assert (cache
[idx
]);
3688 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3694 * mini_parse_debug_option:
3695 * @option: The option to parse.
3697 * Parses debug options for the mono runtime. The options are the same as for
3698 * the MONO_DEBUG environment variable.
3702 mini_parse_debug_option (const char *option
)
3704 // Empty string is ok as consequence of appending ",foo"
3705 // without first checking for empty.
3709 if (!strcmp (option
, "handle-sigint"))
3710 mini_debug_options
.handle_sigint
= TRUE
;
3711 else if (!strcmp (option
, "keep-delegates"))
3712 mini_debug_options
.keep_delegates
= TRUE
;
3713 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3714 mini_debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3715 else if (!strcmp (option
, "collect-pagefault-stats"))
3716 mini_debug_options
.collect_pagefault_stats
= TRUE
;
3717 else if (!strcmp (option
, "break-on-unverified"))
3718 mini_debug_options
.break_on_unverified
= TRUE
;
3719 else if (!strcmp (option
, "no-gdb-backtrace"))
3720 mini_debug_options
.no_gdb_backtrace
= TRUE
;
3721 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
3722 mini_debug_options
.suspend_on_native_crash
= TRUE
;
3723 else if (!strcmp (option
, "suspend-on-exception"))
3724 mini_debug_options
.suspend_on_exception
= TRUE
;
3725 else if (!strcmp (option
, "suspend-on-unhandled"))
3726 mini_debug_options
.suspend_on_unhandled
= TRUE
;
3727 else if (!strcmp (option
, "dont-free-domains"))
3728 mono_dont_free_domains
= TRUE
;
3729 else if (!strcmp (option
, "dyn-runtime-invoke"))
3730 mini_debug_options
.dyn_runtime_invoke
= TRUE
;
3731 else if (!strcmp (option
, "gdb"))
3732 mini_debug_options
.gdb
= TRUE
;
3733 else if (!strcmp (option
, "lldb"))
3734 mini_debug_options
.lldb
= TRUE
;
3735 else if (!strcmp (option
, "explicit-null-checks"))
3736 mini_debug_options
.explicit_null_checks
= TRUE
;
3737 else if (!strcmp (option
, "gen-seq-points"))
3738 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
3739 else if (!strcmp (option
, "gen-compact-seq-points"))
3740 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3741 else if (!strcmp (option
, "no-compact-seq-points"))
3742 mini_debug_options
.no_seq_points_compact_data
= TRUE
;
3743 else if (!strcmp (option
, "single-imm-size"))
3744 mini_debug_options
.single_imm_size
= TRUE
;
3745 else if (!strcmp (option
, "init-stacks"))
3746 mini_debug_options
.init_stacks
= TRUE
;
3747 else if (!strcmp (option
, "casts"))
3748 mini_debug_options
.better_cast_details
= TRUE
;
3749 else if (!strcmp (option
, "soft-breakpoints"))
3750 mini_debug_options
.soft_breakpoints
= TRUE
;
3751 else if (!strcmp (option
, "check-pinvoke-callconv"))
3752 mini_debug_options
.check_pinvoke_callconv
= TRUE
;
3753 else if (!strcmp (option
, "use-fallback-tls"))
3754 mini_debug_options
.use_fallback_tls
= TRUE
;
3755 else if (!strcmp (option
, "debug-domain-unload"))
3756 mono_enable_debug_domain_unload (TRUE
);
3757 else if (!strcmp (option
, "partial-sharing"))
3758 mono_set_partial_sharing_supported (TRUE
);
3759 else if (!strcmp (option
, "align-small-structs"))
3760 mono_align_small_structs
= TRUE
;
3761 else if (!strcmp (option
, "native-debugger-break"))
3762 mini_debug_options
.native_debugger_break
= TRUE
;
3763 else if (!strcmp (option
, "disable_omit_fp"))
3764 mini_debug_options
.disable_omit_fp
= TRUE
;
3765 // This is an internal testing feature.
3766 // Every tail. encountered is required to be optimized.
3768 else if (!strcmp (option
, "test-tailcall-require"))
3769 mini_debug_options
.test_tailcall_require
= TRUE
;
3770 else if (!strcmp (option
, "verbose-gdb"))
3771 mini_debug_options
.verbose_gdb
= TRUE
;
3772 else if (!strncmp (option
, "thread-dump-dir=", 16))
3773 mono_set_thread_dump_dir(g_strdup(option
+ 16));
3774 else if (!strncmp (option
, "aot-skip=", 9)) {
3775 mini_debug_options
.aot_skip_set
= TRUE
;
3776 mini_debug_options
.aot_skip
= atoi (option
+ 9);
3784 mini_parse_debug_options (void)
3786 char *options
= g_getenv ("MONO_DEBUG");
3787 gchar
**args
, **ptr
;
3792 args
= g_strsplit (options
, ",", -1);
3795 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
3796 const char *arg
= *ptr
;
3798 if (!mini_parse_debug_option (arg
)) {
3799 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
3800 // test-tailcall-require is also accepted but not documented.
3801 // empty string is also accepted and ignored as a consequence
3802 // of appending ",foo" without checking for empty.
3803 fprintf (stderr
, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break', 'thread-dump-dir=DIR', 'no-verbose-gdb'.\n");
3812 mini_get_debug_options (void)
3814 return &mini_debug_options
;
3818 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
3820 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3821 gpointer
* desc
= NULL
;
3823 if ((desc
= g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
3825 #if defined(__mono_ppc64__)
3826 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
3832 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
3840 mini_get_addr_from_ftnptr (gpointer descr
)
3842 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3843 return *(gpointer
*)descr
;
3850 register_jit_stats (void)
3852 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
3853 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
3854 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
3855 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
3856 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_interp
);
3857 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_method_to_ir
);
3858 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses
);
3859 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
);
3860 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_long_opts
);
3861 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_typechecks
);
3862 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop
);
3863 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_emulate_ops
);
3864 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches
);
3865 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs
);
3866 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce
);
3867 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_alias_analysis
);
3868 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_if_conversion
);
3869 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_bb_ordering
);
3870 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compile_dominator_info
);
3871 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compute_natural_loops
);
3872 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_insert_safepoints
);
3873 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_compute
);
3874 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_cprop
);
3875 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_deadce
);
3876 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_perform_abc_removal
);
3877 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_remove
);
3878 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop2
);
3879 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs2
);
3880 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce2
);
3881 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches2
);
3882 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_vtype_opts
);
3883 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_array_access_opts
);
3884 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses2
);
3885 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_analyze_liveness
);
3886 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_linear_scan
);
3887 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_arch_allocate_vars
);
3888 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_spill_global_vars
);
3889 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop3
);
3890 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce3
);
3891 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_codegen
);
3892 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_create_jit_info
);
3893 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_gc_create_gc_map
);
3894 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_save_seq_point_info
);
3895 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_time
);
3896 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.basic_blocks
);
3897 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.max_basic_blocks
);
3898 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocate_var
);
3899 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.code_reallocs
);
3900 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_code_size
);
3901 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_seq_points_size
);
3902 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlineable_methods
);
3903 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlined_methods
);
3904 mono_counters_register ("Regvars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.regvars
);
3905 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.locals_stack_size
);
3906 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_lookups
);
3907 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.cil_code_size
);
3908 mono_counters_register ("Native code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.native_code_size
);
3909 mono_counters_register ("Aliases found", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_found
);
3910 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_removed
);
3911 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.loads_eliminated
);
3912 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.stores_eliminated
);
3913 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.optimized_divisions
);
3916 static void runtime_invoke_info_free (gpointer value
);
3919 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
3921 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
3922 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
3924 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
3928 class_method_pair_hash (gconstpointer data
)
3930 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
3932 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
3936 mini_create_jit_domain_info (MonoDomain
*domain
)
3938 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
3940 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3941 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3942 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
3943 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3944 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
3945 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
3946 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3947 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
3948 mono_jit_code_hash_init (&info
->interp_code_hash
);
3950 domain
->runtime_info
= info
;
3954 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
3956 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
3957 g_slist_free (jlist
->list
);
3961 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
3963 GSList
*list
= (GSList
*)value
;
3964 g_slist_free (list
);
3968 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
3970 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
3971 mono_code_manager_destroy (di
->code_mp
);
3976 runtime_invoke_info_free (gpointer value
)
3978 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
3980 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3981 if (info
->dyn_call_info
)
3982 mono_arch_dyn_call_free (info
->dyn_call_info
);
3988 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
3990 g_slist_free (value
);
3994 mini_free_jit_domain_info (MonoDomain
*domain
)
3996 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3998 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
3999 g_hash_table_destroy (info
->jump_target_hash
);
4000 if (info
->jump_target_got_slot_hash
) {
4001 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
4002 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
4004 if (info
->dynamic_code_hash
) {
4005 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
4006 g_hash_table_destroy (info
->dynamic_code_hash
);
4008 g_hash_table_destroy (info
->method_code_hash
);
4009 g_hash_table_destroy (info
->jump_trampoline_hash
);
4010 g_hash_table_destroy (info
->jit_trampoline_hash
);
4011 g_hash_table_destroy (info
->delegate_trampoline_hash
);
4012 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
4013 g_hash_table_destroy (info
->mrgctx_hash
);
4014 g_hash_table_destroy (info
->method_rgctx_hash
);
4015 g_hash_table_destroy (info
->interp_method_pointer_hash
);
4016 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
4017 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
4018 g_hash_table_destroy (info
->seq_points
);
4019 g_hash_table_destroy (info
->arch_seq_points
);
4020 if (info
->agent_info
)
4021 mini_get_dbg_callbacks ()->free_domain_info (domain
);
4022 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
4023 if (info
->llvm_jit_callees
) {
4024 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
4025 g_hash_table_destroy (info
->llvm_jit_callees
);
4027 mono_internal_hash_table_destroy (&info
->interp_code_hash
);
4029 mono_llvm_free_domain_info (domain
);
4032 g_free (domain
->runtime_info
);
4033 domain
->runtime_info
= NULL
;
4036 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4039 code_manager_chunk_new (void *chunk
, int size
)
4041 mono_arch_code_chunk_new (chunk
, size
);
4045 code_manager_chunk_destroy (void *chunk
)
4047 mono_arch_code_chunk_destroy (chunk
);
4054 llvm_init_inner (void)
4056 if (!mono_llvm_load (NULL
))
4067 * Load and initialize LLVM support.
4068 * Return TRUE on success.
4071 mini_llvm_init (void)
4074 static gboolean llvm_inited
;
4075 static gboolean init_result
;
4077 mono_loader_lock_if_inited ();
4079 init_result
= llvm_init_inner ();
4082 mono_loader_unlock_if_inited ();
4090 mini_add_profiler_argument (const char *desc
)
4092 if (!profile_options
)
4093 profile_options
= g_ptr_array_new ();
4095 g_ptr_array_add (profile_options
, (gpointer
) desc
);
4099 static MonoEECallbacks interp_cbs
= {0};
4102 mini_install_interp_callbacks (MonoEECallbacks
*cbs
)
4104 memcpy (&interp_cbs
, cbs
, sizeof (MonoEECallbacks
));
4108 mini_get_interp_callbacks (void)
4113 static MonoDebuggerCallbacks dbg_cbs
;
4116 mini_install_dbg_callbacks (MonoDebuggerCallbacks
*cbs
)
4118 g_assert (cbs
->version
== MONO_DBG_CALLBACKS_VERSION
);
4119 memcpy (&dbg_cbs
, cbs
, sizeof (MonoDebuggerCallbacks
));
4122 MonoDebuggerCallbacks
*
4123 mini_get_dbg_callbacks (void)
4129 mono_ee_api_version (void)
4131 return MONO_EE_API_VERSION
;
4135 mono_interp_entry_from_trampoline (gpointer ccontext
, gpointer imethod
)
4137 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext
, imethod
);
4141 mini_init (const char *filename
, const char *runtime_version
)
4145 MonoRuntimeCallbacks callbacks
;
4146 MonoThreadInfoRuntimeCallbacks ticallbacks
;
4147 MonoCodeManagerCallbacks code_manager_callbacks
;
4149 MONO_VES_INIT_BEGIN ();
4151 CHECKED_MONO_INIT ();
4153 #if defined(__linux__)
4154 if (access ("/proc/self/maps", F_OK
) != 0) {
4155 g_print ("Mono requires /proc to be mounted.\n");
4160 mono_interp_stub_init ();
4161 #ifndef DISABLE_INTERPRETER
4162 if (mono_use_interpreter
)
4163 mono_ee_interp_init (mono_interp_opts_string
);
4166 mono_debugger_agent_stub_init ();
4168 mono_debugger_agent_init ();
4172 mini_get_dbg_callbacks ()->parse_options (sdb_options
);
4174 mono_os_mutex_init_recursive (&jit_mutex
);
4176 mono_cross_helpers_run ();
4178 mono_counters_init ();
4182 mini_jit_init_job_control ();
4184 /* Happens when using the embedding interface */
4185 if (!default_opt_set
)
4186 default_opt
= mono_parse_default_optimizations (NULL
);
4188 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4190 mono_set_generic_sharing_vt_supported (TRUE
);
4193 mono_set_generic_sharing_vt_supported (TRUE
);
4196 mono_tls_init_runtime_keys ();
4198 if (!global_codeman
)
4199 global_codeman
= mono_code_manager_new ();
4201 memset (&callbacks
, 0, sizeof (callbacks
));
4202 callbacks
.create_ftnptr
= mini_create_ftnptr
;
4203 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
4204 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
4205 callbacks
.set_cast_details
= mono_set_cast_details
;
4206 callbacks
.debug_log
= mini_get_dbg_callbacks ()->debug_log
;
4207 callbacks
.debug_log_is_enabled
= mini_get_dbg_callbacks ()->debug_log_is_enabled
;
4208 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
4209 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
4210 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
4211 callbacks
.init_delegate
= mini_init_delegate
;
4212 #define JIT_INVOKE_WORKS
4213 #ifdef JIT_INVOKE_WORKS
4214 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
4216 #define JIT_TRAMPOLINES_WORK
4217 #ifdef JIT_TRAMPOLINES_WORK
4218 callbacks
.compile_method
= mono_jit_compile_method
;
4219 callbacks
.create_jump_trampoline
= mono_create_jump_trampoline
;
4220 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
4221 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
4222 callbacks
.free_method
= mono_jit_free_method
;
4223 #ifndef DISABLE_REMOTING
4224 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
4227 #ifndef DISABLE_REMOTING
4228 if (mono_use_interpreter
)
4229 callbacks
.interp_get_remoting_invoke
= mini_get_interp_callbacks ()->get_remoting_invoke
;
4231 callbacks
.get_weak_field_indexes
= mono_aot_get_weak_field_indexes
;
4234 callbacks
.install_state_summarizer
= mini_register_sigterm_handler
;
4237 mono_install_callbacks (&callbacks
);
4239 memset (&ticallbacks
, 0, sizeof (ticallbacks
));
4240 ticallbacks
.setup_async_callback
= mono_setup_async_callback
;
4241 ticallbacks
.thread_state_init_from_sigctx
= mono_thread_state_init_from_sigctx
;
4242 ticallbacks
.thread_state_init_from_handle
= mono_thread_state_init_from_handle
;
4243 ticallbacks
.thread_state_init
= mono_thread_state_init
;
4246 mono_w32handle_init ();
4249 mono_thread_info_runtime_init (&ticallbacks
);
4251 if (g_hasenv ("MONO_DEBUG")) {
4252 mini_parse_debug_options ();
4255 mono_code_manager_init ();
4257 memset (&code_manager_callbacks
, 0, sizeof (code_manager_callbacks
));
4258 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4259 code_manager_callbacks
.chunk_new
= code_manager_chunk_new
;
4260 code_manager_callbacks
.chunk_destroy
= code_manager_chunk_destroy
;
4262 mono_code_manager_install_callbacks (&code_manager_callbacks
);
4266 mono_arch_cpu_init ();
4270 mono_unwind_init ();
4272 if (mini_get_debug_options ()->lldb
|| g_hasenv ("MONO_LLDB")) {
4273 mono_lldb_init ("");
4274 mono_dont_free_domains
= TRUE
;
4277 #ifdef XDEBUG_ENABLED
4278 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
4280 mono_xdebug_init (mono_xdebug
);
4281 g_free (mono_xdebug
);
4282 /* So methods for multiple domains don't have the same address */
4283 mono_dont_free_domains
= TRUE
;
4284 mono_using_xdebug
= TRUE
;
4285 } else if (mini_get_debug_options ()->gdb
) {
4286 mono_xdebug_init ((char*)"gdb");
4287 mono_dont_free_domains
= TRUE
;
4288 mono_using_xdebug
= TRUE
;
4293 if (mono_use_llvm
) {
4294 if (!mono_llvm_load (NULL
)) {
4295 mono_use_llvm
= FALSE
;
4296 fprintf (stderr
, "Mono Warning: llvm support could not be loaded.\n");
4303 mono_trampolines_init ();
4305 if (default_opt
& MONO_OPT_AOT
)
4308 mini_get_dbg_callbacks ()->init ();
4311 mono_wasm_debugger_init ();
4314 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4315 mono_set_generic_sharing_supported (TRUE
);
4318 mono_thread_info_signals_init ();
4320 #ifndef MONO_CROSS_COMPILE
4321 mono_runtime_install_handlers ();
4323 mono_threads_install_cleanup (mini_thread_cleanup
);
4325 #ifdef JIT_TRAMPOLINES_WORK
4326 mono_install_create_domain_hook (mini_create_jit_domain_info
);
4327 mono_install_free_domain_hook (mini_free_jit_domain_info
);
4329 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
4330 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
4331 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
4333 mono_profiler_state
.context_enable
= mini_profiler_context_enable
;
4334 mono_profiler_state
.context_get_this
= mini_profiler_context_get_this
;
4335 mono_profiler_state
.context_get_argument
= mini_profiler_context_get_argument
;
4336 mono_profiler_state
.context_get_local
= mini_profiler_context_get_local
;
4337 mono_profiler_state
.context_get_result
= mini_profiler_context_get_result
;
4338 mono_profiler_state
.context_free_buffer
= mini_profiler_context_free_buffer
;
4340 if (profile_options
)
4341 for (guint i
= 0; i
< profile_options
->len
; i
++)
4342 mono_profiler_load ((const char *) g_ptr_array_index (profile_options
, i
));
4344 mono_profiler_started ();
4346 if (mini_debug_options
.collect_pagefault_stats
)
4347 mono_aot_set_make_unreadable (TRUE
);
4349 if (runtime_version
)
4350 domain
= mono_init_version (filename
, runtime_version
);
4352 domain
= mono_init_from_assembly (filename
, filename
);
4354 if (mono_aot_only
) {
4355 /* This helps catch code allocation requests */
4356 mono_code_manager_set_read_only (domain
->code_mp
);
4357 mono_marshal_use_aot_wrappers (TRUE
);
4360 if (mono_llvm_only
) {
4361 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline
);
4362 mono_set_always_build_imt_trampolines (TRUE
);
4363 } else if (mono_aot_only
) {
4364 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
4366 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
4369 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4370 mono_arch_finish_init ();
4374 /* This must come after mono_init () in the aot-only case */
4375 mono_exceptions_init ();
4377 /* This should come after mono_init () too */
4381 mono_create_helper_signatures ();
4384 register_jit_stats ();
4386 #define JIT_CALLS_WORK
4387 #ifdef JIT_CALLS_WORK
4388 /* Needs to be called here since register_jit_icall depends on it */
4389 mono_marshal_init ();
4391 mono_arch_register_lowlevel_calls ();
4395 mono_generic_sharing_init ();
4398 #ifdef MONO_ARCH_SIMD_INTRINSICS
4399 mono_simd_intrinsics_init ();
4402 mono_tasklets_init ();
4404 register_trampolines (domain
);
4406 if (mono_compile_aot
)
4408 * Avoid running managed code when AOT compiling, since the platform
4409 * might only support aot-only execution.
4411 mono_runtime_set_no_exec (TRUE
);
4413 mono_mem_account_register_counters ();
4415 #define JIT_RUNTIME_WORKS
4416 #ifdef JIT_RUNTIME_WORKS
4417 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
4418 mono_runtime_init_checked (domain
, mono_thread_start_cb
, mono_thread_attach_cb
, error
);
4419 mono_error_assert_ok (error
);
4420 mono_thread_attach (domain
);
4421 MONO_PROFILER_RAISE (thread_name
, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4424 if (mono_profiler_sampling_enabled ())
4425 mono_runtime_setup_stat_profiler ();
4427 MONO_PROFILER_RAISE (runtime_initialized
, ());
4429 MONO_VES_INIT_END ();
4435 register_icalls (void)
4437 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4438 ves_icall_get_frame_info
);
4439 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4440 ves_icall_get_trace
);
4441 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4442 mono_runtime_install_handlers
);
4443 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4444 mono_runtime_cleanup_handlers
);
4446 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4447 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4448 mini_get_dbg_callbacks ()->unhandled_exception
);
4452 * It's important that we pass `TRUE` as the last argument here, as
4453 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4454 * *did* emit a wrapper, we'd be looking at infinite recursion since
4455 * the wrapper would call the icall which would call the wrapper and
4458 register_icall (mono_profiler_raise_method_enter
, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE
);
4459 register_icall (mono_profiler_raise_method_leave
, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE
);
4460 register_icall (mono_profiler_raise_method_tail_call
, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE
);
4461 register_icall (mono_profiler_raise_exception_clause
, "mono_profiler_raise_exception_clause", "void ptr int int object", TRUE
);
4463 register_icall (mono_trace_enter_method
, "mono_trace_enter_method", NULL
, TRUE
);
4464 register_icall (mono_trace_leave_method
, "mono_trace_leave_method", NULL
, TRUE
);
4465 register_icall (mono_get_lmf_addr
, "mono_get_lmf_addr", "ptr", TRUE
);
4466 register_icall (mono_jit_thread_attach
, "mono_jit_thread_attach", "ptr ptr", TRUE
);
4467 register_icall (mono_jit_set_domain
, "mono_jit_set_domain", "void ptr", TRUE
);
4468 register_icall (mono_domain_get
, "mono_domain_get", "ptr", TRUE
);
4470 register_icall (mono_llvm_throw_exception
, "mono_llvm_throw_exception", "void object", TRUE
);
4471 register_icall (mono_llvm_rethrow_exception
, "mono_llvm_rethrow_exception", "void object", TRUE
);
4472 register_icall (mono_llvm_resume_exception
, "mono_llvm_resume_exception", "void", TRUE
);
4473 register_icall (mono_llvm_match_exception
, "mono_llvm_match_exception", "int ptr int int", TRUE
);
4474 register_icall (mono_llvm_clear_exception
, "mono_llvm_clear_exception", NULL
, TRUE
);
4475 register_icall (mono_llvm_load_exception
, "mono_llvm_load_exception", "object", TRUE
);
4476 register_icall (mono_llvm_throw_corlib_exception
, "mono_llvm_throw_corlib_exception", "void int", TRUE
);
4477 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4478 register_icall (mono_llvm_set_unhandled_exception_handler
, "mono_llvm_set_unhandled_exception_handler", NULL
, TRUE
);
4480 // FIXME: This is broken
4481 register_icall (mono_debug_personality
, "mono_debug_personality", "int int int ptr ptr ptr", TRUE
);
4484 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE
);
4485 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE
);
4486 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE
);
4487 register_icall (mono_thread_get_undeniable_exception
, "mono_thread_get_undeniable_exception", "object", FALSE
);
4488 register_icall (ves_icall_thread_finish_async_abort
, "ves_icall_thread_finish_async_abort", "void", FALSE
);
4489 register_icall (mono_thread_interruption_checkpoint
, "mono_thread_interruption_checkpoint", "object", FALSE
);
4490 register_icall (mono_thread_force_interruption_checkpoint_noraise
, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE
);
4492 if (mono_threads_are_safepoints_enabled ())
4493 register_icall (mono_threads_state_poll
, "mono_threads_state_poll", "void", FALSE
);
4495 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4496 register_opcode_emulation (OP_LMUL
, "__emul_lmul", "long long long", mono_llmult
, "mono_llmult", FALSE
);
4497 register_opcode_emulation (OP_LDIV
, "__emul_ldiv", "long long long", mono_lldiv
, "mono_lldiv", FALSE
);
4498 register_opcode_emulation (OP_LDIV_UN
, "__emul_ldiv_un", "long long long", mono_lldiv_un
, "mono_lldiv_un", FALSE
);
4499 register_opcode_emulation (OP_LREM
, "__emul_lrem", "long long long", mono_llrem
, "mono_llrem", FALSE
);
4500 register_opcode_emulation (OP_LREM_UN
, "__emul_lrem_un", "long long long", mono_llrem_un
, "mono_llrem_un", FALSE
);
4502 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4503 register_opcode_emulation (OP_LMUL_OVF_UN
, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un
, "mono_llmult_ovf_un", FALSE
);
4504 register_opcode_emulation (OP_LMUL_OVF
, "__emul_lmul_ovf", "long long long", mono_llmult_ovf
, "mono_llmult_ovf", FALSE
);
4507 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4508 register_opcode_emulation (OP_LSHL
, "__emul_lshl", "long long int32", mono_lshl
, "mono_lshl", TRUE
);
4509 register_opcode_emulation (OP_LSHR
, "__emul_lshr", "long long int32", mono_lshr
, "mono_lshr", TRUE
);
4510 register_opcode_emulation (OP_LSHR_UN
, "__emul_lshr_un", "long long int32", mono_lshr_un
, "mono_lshr_un", TRUE
);
4513 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4514 register_opcode_emulation (OP_IDIV
, "__emul_op_idiv", "int32 int32 int32", mono_idiv
, "mono_idiv", FALSE
);
4515 register_opcode_emulation (OP_IDIV_UN
, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un
, "mono_idiv_un", FALSE
);
4516 register_opcode_emulation (OP_IREM
, "__emul_op_irem", "int32 int32 int32", mono_irem
, "mono_irem", FALSE
);
4517 register_opcode_emulation (OP_IREM_UN
, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un
, "mono_irem_un", FALSE
);
4520 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4521 register_opcode_emulation (OP_IMUL
, "__emul_op_imul", "int32 int32 int32", mono_imul
, "mono_imul", TRUE
);
4524 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4525 register_opcode_emulation (OP_IMUL_OVF
, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf
, "mono_imul_ovf", FALSE
);
4526 register_opcode_emulation (OP_IMUL_OVF_UN
, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un
, "mono_imul_ovf_un", FALSE
);
4529 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4530 register_opcode_emulation (OP_FDIV
, "__emul_fdiv", "double double double", mono_fdiv
, "mono_fdiv", FALSE
);
4533 register_opcode_emulation (OP_FCONV_TO_U8
, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8
, "mono_fconv_u8", FALSE
);
4534 register_opcode_emulation (OP_RCONV_TO_U8
, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8
, "mono_rconv_u8", FALSE
);
4535 register_opcode_emulation (OP_FCONV_TO_U4
, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4
, "mono_fconv_u4", FALSE
);
4536 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8
, "mono_fconv_ovf_i8", FALSE
);
4537 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8
, "mono_fconv_ovf_u8", FALSE
);
4538 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8
, "mono_rconv_ovf_i8", FALSE
);
4539 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8
, "mono_rconv_ovf_u8", FALSE
);
4542 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4543 register_opcode_emulation (OP_FCONV_TO_I8
, "__emul_fconv_to_i8", "long double", mono_fconv_i8
, "mono_fconv_i8", FALSE
);
4544 register_opcode_emulation (OP_RCONV_TO_I8
, "__emul_rconv_to_i8", "long float", mono_rconv_i8
, "mono_rconv_i8", FALSE
);
4547 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4548 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
);
4550 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4551 register_opcode_emulation (OP_LCONV_TO_R8
, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8
, "mono_lconv_to_r8", FALSE
);
4553 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4554 register_opcode_emulation (OP_LCONV_TO_R4
, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4
, "mono_lconv_to_r4", FALSE
);
4556 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4557 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
);
4559 #ifdef MONO_ARCH_EMULATE_FREM
4560 register_opcode_emulation (OP_FREM
, "__emul_frem", "double double double", fmod
, "fmod", FALSE
);
4561 register_opcode_emulation (OP_RREM
, "__emul_rrem", "float float float", fmodf
, "fmodf", FALSE
);
4564 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4565 if (mono_arch_is_soft_float ()) {
4566 register_opcode_emulation (OP_FSUB
, "__emul_fsub", "double double double", mono_fsub
, "mono_fsub", FALSE
);
4567 register_opcode_emulation (OP_FADD
, "__emul_fadd", "double double double", mono_fadd
, "mono_fadd", FALSE
);
4568 register_opcode_emulation (OP_FMUL
, "__emul_fmul", "double double double", mono_fmul
, "mono_fmul", FALSE
);
4569 register_opcode_emulation (OP_FNEG
, "__emul_fneg", "double double", mono_fneg
, "mono_fneg", FALSE
);
4570 register_opcode_emulation (OP_ICONV_TO_R8
, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8
, "mono_conv_to_r8", FALSE
);
4571 register_opcode_emulation (OP_ICONV_TO_R4
, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4
, "mono_conv_to_r4", FALSE
);
4572 register_opcode_emulation (OP_FCONV_TO_R4
, "__emul_fconv_to_r4", "double double", mono_fconv_r4
, "mono_fconv_r4", FALSE
);
4573 register_opcode_emulation (OP_FCONV_TO_I1
, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1
, "mono_fconv_i1", FALSE
);
4574 register_opcode_emulation (OP_FCONV_TO_I2
, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2
, "mono_fconv_i2", FALSE
);
4575 register_opcode_emulation (OP_FCONV_TO_I4
, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4576 register_opcode_emulation (OP_FCONV_TO_U1
, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1
, "mono_fconv_u1", FALSE
);
4577 register_opcode_emulation (OP_FCONV_TO_U2
, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2
, "mono_fconv_u2", FALSE
);
4579 #if SIZEOF_VOID_P == 4
4580 register_opcode_emulation (OP_FCONV_TO_I
, "__emul_fconv_to_i", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4583 register_opcode_emulation (OP_FBEQ
, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq
, "mono_fcmp_eq", FALSE
);
4584 register_opcode_emulation (OP_FBLT
, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt
, "mono_fcmp_lt", FALSE
);
4585 register_opcode_emulation (OP_FBGT
, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt
, "mono_fcmp_gt", FALSE
);
4586 register_opcode_emulation (OP_FBLE
, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le
, "mono_fcmp_le", FALSE
);
4587 register_opcode_emulation (OP_FBGE
, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge
, "mono_fcmp_ge", FALSE
);
4588 register_opcode_emulation (OP_FBNE_UN
, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un
, "mono_fcmp_ne_un", FALSE
);
4589 register_opcode_emulation (OP_FBLT_UN
, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un
, "mono_fcmp_lt_un", FALSE
);
4590 register_opcode_emulation (OP_FBGT_UN
, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un
, "mono_fcmp_gt_un", FALSE
);
4591 register_opcode_emulation (OP_FBLE_UN
, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un
, "mono_fcmp_le_un", FALSE
);
4592 register_opcode_emulation (OP_FBGE_UN
, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un
, "mono_fcmp_ge_un", FALSE
);
4594 register_opcode_emulation (OP_FCEQ
, "__emul_fcmp_ceq", "uint32 double double", mono_fceq
, "mono_fceq", FALSE
);
4595 register_opcode_emulation (OP_FCGT
, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt
, "mono_fcgt", FALSE
);
4596 register_opcode_emulation (OP_FCGT_UN
, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un
, "mono_fcgt_un", FALSE
);
4597 register_opcode_emulation (OP_FCLT
, "__emul_fcmp_clt", "uint32 double double", mono_fclt
, "mono_fclt", FALSE
);
4598 register_opcode_emulation (OP_FCLT_UN
, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un
, "mono_fclt_un", FALSE
);
4600 register_icall (mono_fload_r4
, "mono_fload_r4", "double ptr", FALSE
);
4601 register_icall (mono_fstore_r4
, "mono_fstore_r4", "void double ptr", FALSE
);
4602 register_icall (mono_fload_r4_arg
, "mono_fload_r4_arg", "uint32 double", FALSE
);
4603 register_icall (mono_isfinite
, "mono_isfinite", "uint32 double", FALSE
);
4606 register_icall (mono_ckfinite
, "mono_ckfinite", "double double", FALSE
);
4608 #ifdef COMPRESSED_INTERFACE_BITMAP
4609 register_icall (mono_class_interface_match
, "mono_class_interface_match", "uint32 ptr int32", TRUE
);
4612 #if SIZEOF_REGISTER == 4
4613 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4
, "mono_fconv_u4", TRUE
);
4615 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "ulong double", mono_fconv_u8
, "mono_fconv_u8", TRUE
);
4618 /* other jit icalls */
4619 register_icall (ves_icall_mono_delegate_ctor
, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE
);
4620 register_icall (ves_icall_mono_delegate_ctor_interp
, "ves_icall_mono_delegate_ctor_interp", "void object object ptr", FALSE
);
4621 register_icall (mono_class_static_field_address
, "mono_class_static_field_address",
4622 "ptr ptr ptr", FALSE
);
4623 register_icall (mono_ldtoken_wrapper
, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE
);
4624 register_icall (mono_ldtoken_wrapper_generic_shared
, "mono_ldtoken_wrapper_generic_shared",
4625 "ptr ptr ptr ptr", FALSE
);
4626 register_icall (mono_get_special_static_data
, "mono_get_special_static_data", "ptr int", FALSE
);
4627 register_icall (ves_icall_mono_ldstr
, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE
);
4628 register_icall (mono_helper_stelem_ref_check
, "mono_helper_stelem_ref_check", "void object object", FALSE
);
4629 register_icall (ves_icall_object_new
, "ves_icall_object_new", "object ptr ptr", FALSE
);
4630 register_icall (ves_icall_object_new_specific
, "ves_icall_object_new_specific", "object ptr", FALSE
);
4631 register_icall (ves_icall_array_new
, "ves_icall_array_new", "object ptr ptr int32", FALSE
);
4632 register_icall (ves_icall_array_new_specific
, "ves_icall_array_new_specific", "object ptr int32", FALSE
);
4633 register_icall (ves_icall_runtime_class_init
, "ves_icall_runtime_class_init", "void ptr", FALSE
);
4634 register_icall (mono_ldftn
, "mono_ldftn", "ptr ptr", FALSE
);
4635 register_icall (mono_ldvirtfn
, "mono_ldvirtfn", "ptr object ptr", FALSE
);
4636 register_icall (mono_ldvirtfn_gshared
, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE
);
4637 register_icall (mono_helper_compile_generic_method
, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE
);
4638 register_icall (mono_helper_ldstr
, "mono_helper_ldstr", "object ptr int", FALSE
);
4639 register_icall (mono_helper_ldstr_mscorlib
, "mono_helper_ldstr_mscorlib", "object int", FALSE
);
4640 register_icall (mono_helper_newobj_mscorlib
, "mono_helper_newobj_mscorlib", "object int", FALSE
);
4641 register_icall (mono_value_copy
, "mono_value_copy", "void ptr ptr ptr", FALSE
);
4642 register_icall (mono_object_castclass_unbox
, "mono_object_castclass_unbox", "object object ptr", FALSE
);
4643 register_icall (mono_break
, "mono_break", NULL
, TRUE
);
4644 register_icall (mono_create_corlib_exception_0
, "mono_create_corlib_exception_0", "object int", TRUE
);
4645 register_icall (mono_create_corlib_exception_1
, "mono_create_corlib_exception_1", "object int object", TRUE
);
4646 register_icall (mono_create_corlib_exception_2
, "mono_create_corlib_exception_2", "object int object object", TRUE
);
4647 register_icall (mono_array_new_1
, "mono_array_new_1", "object ptr int", FALSE
);
4648 register_icall (mono_array_new_2
, "mono_array_new_2", "object ptr int int", FALSE
);
4649 register_icall (mono_array_new_3
, "mono_array_new_3", "object ptr int int int", FALSE
);
4650 register_icall (mono_array_new_4
, "mono_array_new_4", "object ptr int int int int", FALSE
);
4651 register_icall (mono_get_native_calli_wrapper
, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE
);
4652 register_icall (mono_resume_unwind
, "mono_resume_unwind", "void", TRUE
);
4653 register_icall (mono_gsharedvt_constrained_call
, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE
);
4654 register_icall (mono_gsharedvt_value_copy
, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE
);
4656 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4657 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4659 register_icall (mono_object_castclass_with_cache
, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE
);
4660 register_icall (mono_object_isinst_with_cache
, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE
);
4661 register_icall (mono_generic_class_init
, "mono_generic_class_init", "void ptr", FALSE
);
4662 register_icall (mono_fill_class_rgctx
, "mono_fill_class_rgctx", "ptr ptr int", FALSE
);
4663 register_icall (mono_fill_method_rgctx
, "mono_fill_method_rgctx", "ptr ptr int", FALSE
);
4665 register_icall (mini_get_dbg_callbacks ()->user_break
, "mono_debugger_agent_user_break", "void", FALSE
);
4667 register_icall (mono_aot_init_llvm_method
, "mono_aot_init_llvm_method", "void ptr int", TRUE
);
4668 register_icall (mono_aot_init_gshared_method_this
, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE
);
4669 register_icall (mono_aot_init_gshared_method_mrgctx
, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE
);
4670 register_icall (mono_aot_init_gshared_method_vtable
, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE
);
4672 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt
, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4673 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt
, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4674 register_icall_no_wrapper (mono_resolve_generic_virtual_call
, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4675 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call
, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4676 /* This needs a wrapper so it can have a preserveall cconv */
4677 register_icall (mono_init_vtable_slot
, "mono_init_vtable_slot", "ptr ptr int", FALSE
);
4678 register_icall (mono_llvmonly_init_delegate
, "mono_llvmonly_init_delegate", "void object", TRUE
);
4679 register_icall (mono_llvmonly_init_delegate_virtual
, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE
);
4680 register_icall (mono_get_assembly_object
, "mono_get_assembly_object", "object ptr", TRUE
);
4681 register_icall (mono_get_method_object
, "mono_get_method_object", "object ptr", TRUE
);
4682 register_icall (mono_throw_method_access
, "mono_throw_method_access", "void ptr ptr", FALSE
);
4683 register_icall_no_wrapper (mono_dummy_jit_icall
, "mono_dummy_jit_icall", "void");
4685 register_icall_with_wrapper (mono_monitor_enter_internal
, "mono_monitor_enter_internal", "int32 obj");
4686 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, "mono_monitor_enter_v4_internal", "void obj ptr");
4687 register_icall_no_wrapper (mono_monitor_enter_fast
, "mono_monitor_enter_fast", "int obj");
4688 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, "mono_monitor_enter_v4_fast", "int obj ptr");
4691 register_icall (pthread_getspecific
, "pthread_getspecific", "ptr ptr", TRUE
);
4693 /* Register tls icalls */
4694 register_icall_no_wrapper (mono_tls_get_thread
, "mono_tls_get_thread", "ptr");
4695 register_icall_no_wrapper (mono_tls_get_jit_tls
, "mono_tls_get_jit_tls", "ptr");
4696 register_icall_no_wrapper (mono_tls_get_domain
, "mono_tls_get_domain", "ptr");
4697 register_icall_no_wrapper (mono_tls_get_sgen_thread_info
, "mono_tls_get_sgen_thread_info", "ptr");
4698 register_icall_no_wrapper (mono_tls_get_lmf_addr
, "mono_tls_get_lmf_addr", "ptr");
4699 register_icall_no_wrapper (mono_tls_set_thread
, "mono_tls_set_thread", "void ptr");
4700 register_icall_no_wrapper (mono_tls_set_jit_tls
, "mono_tls_set_jit_tls", "void ptr");
4701 register_icall_no_wrapper (mono_tls_set_domain
, "mono_tls_set_domain", "void ptr");
4702 register_icall_no_wrapper (mono_tls_set_sgen_thread_info
, "mono_tls_set_sgen_thread_info", "void ptr");
4703 register_icall_no_wrapper (mono_tls_set_lmf_addr
, "mono_tls_set_lmf_addr", "void ptr");
4705 register_icall_no_wrapper (mono_interp_entry_from_trampoline
, "mono_interp_entry_from_trampoline", "void ptr ptr");
4707 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4708 mono_arch_register_icall ();
4712 MonoJitStats mono_jit_stats
= {0};
4715 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4716 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4718 MONO_NO_SANITIZE_THREAD
4720 print_jit_stats (void)
4722 if (mono_jit_stats
.enabled
) {
4723 g_print ("Mono Jit statistics\n");
4724 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/ 100.0,
4725 mono_jit_stats
.max_ratio_method
);
4726 g_print ("Biggest method: %" G_GINT32_FORMAT
" (%s)\n", mono_jit_stats
.biggest_method_size
,
4727 mono_jit_stats
.biggest_method
);
4729 g_print ("Delegates created: %" G_GINT32_FORMAT
"\n", mono_stats
.delegate_creations
);
4730 g_print ("Initialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.initialized_class_count
);
4731 g_print ("Used classes: %" G_GINT32_FORMAT
"\n", mono_stats
.used_class_count
);
4732 g_print ("Generic vtables: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_vtable_count
);
4733 g_print ("Methods: %" G_GINT32_FORMAT
"\n", mono_stats
.method_count
);
4734 g_print ("Static data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_static_data_size
);
4735 g_print ("VTable data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_vtable_size
);
4736 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4738 g_print ("\nInitialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_class_count
);
4739 g_print ("Inflated types: %" G_GINT32_FORMAT
"\n", mono_stats
.inflated_type_count
);
4740 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4742 g_print ("Sharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_sharable_methods
);
4743 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_unsharable_methods
);
4744 g_print ("Shared generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_shared_methods
);
4745 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.gsharedvt_methods
);
4747 g_print ("IMT tables size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_tables_size
);
4748 g_print ("IMT number of tables: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_tables
);
4749 g_print ("IMT number of methods: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_methods
);
4750 g_print ("IMT used slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_used_slots
);
4751 g_print ("IMT colliding slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_slots_with_collisions
);
4752 g_print ("IMT max collisions: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_max_collisions_in_slot
);
4753 g_print ("IMT methods at max col: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_method_count_when_max_collisions
);
4754 g_print ("IMT trampolines size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_trampolines_size
);
4756 g_print ("JIT info table inserts: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_insert_count
);
4757 g_print ("JIT info table removes: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_remove_count
);
4758 g_print ("JIT info table lookups: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_lookup_count
);
4760 g_free (mono_jit_stats
.max_ratio_method
);
4761 mono_jit_stats
.max_ratio_method
= NULL
;
4762 g_free (mono_jit_stats
.biggest_method
);
4763 mono_jit_stats
.biggest_method
= NULL
;
4768 mini_cleanup (MonoDomain
*domain
)
4770 if (mono_profiler_sampling_enabled ())
4771 mono_runtime_shutdown_stat_profiler ();
4773 MONO_PROFILER_RAISE (runtime_shutdown_begin
, ());
4776 mono_cominterop_release_all_rcws ();
4779 #ifndef MONO_CROSS_COMPILE
4781 * mono_domain_finalize () needs to be called early since it needs the
4782 * execution engine still fully working (it may invoke managed finalizers).
4784 mono_domain_finalize (domain
, 2000);
4787 /* This accesses metadata so needs to be called before runtime shutdown */
4790 #ifndef MONO_CROSS_COMPILE
4791 mono_runtime_cleanup (domain
);
4794 mono_threadpool_cleanup ();
4796 MONO_PROFILER_RAISE (runtime_shutdown_end
, ());
4798 mono_profiler_cleanup ();
4800 if (profile_options
)
4801 g_ptr_array_free (profile_options
, TRUE
);
4803 free_jit_tls_data ((MonoJitTlsData
*)mono_tls_get_jit_tls ());
4805 mono_icall_cleanup ();
4807 mono_runtime_cleanup_handlers ();
4809 #ifndef MONO_CROSS_COMPILE
4810 mono_domain_free (domain
, TRUE
);
4815 mono_llvm_cleanup ();
4818 mono_aot_cleanup ();
4820 mono_trampolines_cleanup ();
4822 mono_unwind_cleanup ();
4824 mono_code_manager_destroy (global_codeman
);
4825 g_free (vtable_trampolines
);
4827 mini_jit_cleanup ();
4829 mono_tramp_info_cleanup ();
4831 mono_arch_cleanup ();
4833 mono_generic_sharing_cleanup ();
4837 mono_trace_cleanup ();
4839 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, stdout
);
4841 if (mono_inject_async_exc_method
)
4842 mono_method_desc_free (mono_inject_async_exc_method
);
4844 mono_tls_free_keys ();
4846 mono_os_mutex_destroy (&jit_mutex
);
4848 mono_code_manager_cleanup ();
4851 mono_w32handle_cleanup ();
4856 mono_set_defaults (int verbose_level
, guint32 opts
)
4858 mini_verbose
= verbose_level
;
4859 mono_set_optimizations (opts
);
4863 mono_disable_optimizations (guint32 opts
)
4865 default_opt
&= ~opts
;
4869 mono_set_optimizations (guint32 opts
)
4872 default_opt_set
= TRUE
;
4873 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4874 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
4877 mono_set_generic_sharing_vt_supported (TRUE
);
4882 mono_set_verbose_level (guint32 level
)
4884 mini_verbose
= level
;
4888 * mono_get_runtime_build_info:
4889 * The returned string is owned by the caller. The returned string
4890 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4891 * \returns the runtime version + build date in string format.
4894 mono_get_runtime_build_info (void)
4896 if (mono_build_date
)
4897 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
4899 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
4903 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
4905 GHashTable
*assemblies
= (GHashTable
*)user_data
;
4906 MonoImage
*image
= mono_assembly_get_image (ass
);
4907 MonoMethod
*method
, *invoke
;
4910 if (g_hash_table_lookup (assemblies
, ass
))
4913 g_hash_table_insert (assemblies
, ass
, ass
);
4915 if (mini_verbose
> 0)
4916 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
4918 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
4921 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, error
);
4923 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4926 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
4928 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
4932 if (mini_verbose
> 1) {
4933 char * desc
= mono_method_full_name (method
, TRUE
);
4934 g_print ("Compiling %d %s\n", count
, desc
);
4937 mono_compile_method_checked (method
, error
);
4938 if (!is_ok (error
)) {
4939 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4942 if (strcmp (method
->name
, "Finalize") == 0) {
4943 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4944 mono_compile_method_checked (invoke
, error
);
4945 mono_error_assert_ok (error
);
4947 #ifndef DISABLE_REMOTING
4948 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature (method
)->hasthis
) {
4949 invoke
= mono_marshal_get_remoting_invoke_with_check (method
, error
);
4950 mono_error_assert_ok (error
);
4951 mono_compile_method_checked (invoke
, error
);
4952 mono_error_assert_ok (error
);
4957 /* Load and precompile referenced assemblies as well */
4958 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
4959 mono_assembly_load_reference (image
, i
);
4960 if (image
->references
[i
])
4961 mono_precompile_assembly (image
->references
[i
], assemblies
);
4965 void mono_precompile_assemblies ()
4967 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
4969 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
4971 g_hash_table_destroy (assemblies
);
4976 * Have to export this for AOT.
4979 mono_personality (void)
4982 g_assert_not_reached ();
4986 static MonoBreakPolicy
4987 always_insert_breakpoint (MonoMethod
*method
)
4989 return MONO_BREAK_POLICY_ALWAYS
;
4992 static MonoBreakPolicyFunc break_policy_func
= always_insert_breakpoint
;
4995 * mono_set_break_policy:
4996 * \param policy_callback the new callback function
4998 * Allow embedders to decide whether to actually obey breakpoint instructions
4999 * (both break IL instructions and \c Debugger.Break method calls), for example
5000 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5001 * untrusted or semi-trusted code.
5003 * \p policy_callback will be called every time a break point instruction needs to
5004 * be inserted with the method argument being the method that calls \c Debugger.Break
5005 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5006 * if it wants the breakpoint to not be effective in the given method.
5007 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5010 mono_set_break_policy (MonoBreakPolicyFunc policy_callback
)
5012 if (policy_callback
)
5013 break_policy_func
= policy_callback
;
5015 break_policy_func
= always_insert_breakpoint
;
5019 mini_should_insert_breakpoint (MonoMethod
*method
)
5021 switch (break_policy_func (method
)) {
5022 case MONO_BREAK_POLICY_ALWAYS
:
5024 case MONO_BREAK_POLICY_NEVER
:
5026 case MONO_BREAK_POLICY_ON_DBG
:
5027 g_warning ("mdb no longer supported");
5030 g_warning ("Incorrect value returned from break policy callback");
5035 // Custom handlers currently only implemented by Windows.
5038 mono_runtime_install_custom_handlers (const char *handlers
)
5044 mono_runtime_install_custom_handlers_usage (void)
5047 "Custom Handlers:\n"
5048 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5049 " separated list of available handlers to install.\n"
5051 "No handlers supported on current platform.\n");
5053 #endif /* HOST_WIN32 */