3 * Runtime code for the JIT
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2002-2003 Ximian, Inc.
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/assembly-internals.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/tokentype.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/metadata/threads.h>
41 #include <mono/metadata/appdomain.h>
42 #include <mono/metadata/debug-helpers.h>
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/metadata/icall-internals.h>
55 #define MONO_MATH_DECLARE_ALL 1
56 #include <mono/utils/mono-math.h>
57 #include <mono/utils/mono-compiler.h>
58 #include <mono/utils/mono-counters.h>
59 #include <mono/utils/mono-error-internals.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-mmap.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-tls.h>
64 #include <mono/utils/mono-hwcap.h>
65 #include <mono/utils/dtrace.h>
66 #include <mono/utils/mono-signal-handler.h>
67 #include <mono/utils/mono-threads.h>
68 #include <mono/utils/mono-threads-coop.h>
69 #include <mono/utils/checked-build.h>
70 #include <mono/utils/mono-compiler.h>
71 #include <mono/utils/mono-proclib.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/threadpool.h>
76 #include "seq-points.h"
82 #include "aot-compiler.h"
83 #include "aot-runtime.h"
84 #include "llvmonly-runtime.h"
86 #include "jit-icalls.h"
89 #include "mini-llvm.h"
90 #include "debugger-agent.h"
92 #include "mini-runtime.h"
93 #include "interp/interp.h"
95 #ifdef MONO_ARCH_LLVM_SUPPORTED
97 #include "mini-llvm-cpp.h"
102 static guint32 default_opt
= 0;
103 static gboolean default_opt_set
= FALSE
;
105 gboolean mono_compile_aot
= FALSE
;
106 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
107 gboolean mono_aot_only
= FALSE
;
108 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
109 gboolean mono_llvm_only
= FALSE
;
110 /* By default, don't require AOT but attempt to probe */
111 MonoAotMode mono_aot_mode
= MONO_AOT_MODE_NORMAL
;
112 MonoEEFeatures mono_ee_features
;
114 const char *mono_build_date
;
115 gboolean mono_do_signal_chaining
;
116 gboolean mono_do_crash_chaining
;
117 int mini_verbose
= 0;
120 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
121 * it can load AOT code compiled by LLVM.
123 gboolean mono_use_llvm
= FALSE
;
125 gboolean mono_use_interpreter
= FALSE
;
126 const char *mono_interp_opts_string
= NULL
;
128 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
129 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
130 static mono_mutex_t jit_mutex
;
132 static MonoCodeManager
*global_codeman
;
134 MonoDebugOptions mini_debug_options
;
137 #ifdef VALGRIND_JIT_REGISTER_MAP
138 int valgrind_register
;
140 GList
* mono_aot_paths
;
142 static GPtrArray
*profile_options
;
144 static GSList
*tramp_infos
;
145 GSList
*mono_interp_only_classes
;
147 static void register_icalls (void);
150 mono_running_on_valgrind (void)
153 if (RUNNING_ON_VALGRIND
){
154 #ifdef VALGRIND_JIT_REGISTER_MAP
155 valgrind_register
= TRUE
;
169 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
171 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
174 ud
->method
= (MonoMethod
*)key
;
179 mono_get_method_from_ip (void *ip
)
185 MonoDomain
*domain
= mono_domain_get ();
186 MonoDebugSourceLocation
*location
;
187 FindTrampUserData user_data
;
190 domain
= mono_get_root_domain ();
192 ji
= mono_jit_info_table_find_internal (domain
, ip
, TRUE
, TRUE
);
195 user_data
.method
= NULL
;
196 mono_domain_lock (domain
);
197 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
198 mono_domain_unlock (domain
);
199 if (user_data
.method
) {
200 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
201 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
207 } else if (ji
->is_trampoline
) {
208 res
= g_strdup_printf ("<%p - %s trampoline>", ip
, ji
->d
.tramp_info
->name
);
212 method
= jinfo_get_method (ji
);
213 method_name
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_IL
);
214 location
= mono_debug_lookup_source_location (method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
216 char *file_loc
= NULL
;
218 file_loc
= g_strdup_printf ("[%s :: %du]", location
->source_file
, location
->row
);
220 res
= g_strdup_printf (" %s [{%p} + 0x%x] %s (%p %p) [%p - %s]", method_name
, method
, (int)((char*)ip
- (char*)ji
->code_start
), file_loc
? file_loc
: "", ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, domain
, domain
->friendly_name
);
222 mono_debug_free_source_location (location
);
223 g_free (method_name
);
231 * \param ip an instruction pointer address
233 * This method is used from a debugger to get the name of the
234 * method at address \p ip. This routine is typically invoked from
235 * a debugger like this:
237 * (gdb) print mono_pmip ($pc)
239 * \returns the name of the method at address \p ip.
244 return mono_get_method_from_ip (ip
);
248 * mono_print_method_from_ip:
249 * \param ip an instruction pointer address
251 * This method is used from a debugger to get the name of the
252 * method at address \p ip.
254 * This prints the name of the method at address \p ip in the standard
255 * output. Unlike \c mono_pmip which returns a string, this routine
256 * prints the value on the standard output.
259 mono_print_method_from_ip (void *ip
)
263 MonoDebugSourceLocation
*source
;
264 MonoDomain
*domain
= mono_domain_get ();
265 MonoDomain
*target_domain
= mono_domain_get ();
266 FindTrampUserData user_data
;
267 MonoGenericSharingContext
*gsctx
;
268 const char *shared_type
;
271 domain
= mono_get_root_domain ();
272 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
273 if (ji
&& ji
->is_trampoline
) {
274 MonoTrampInfo
*tinfo
= ji
->d
.tramp_info
;
276 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip
, (int)((guint8
*)ip
- tinfo
->code
), tinfo
->name
);
282 user_data
.method
= NULL
;
283 mono_domain_lock (domain
);
284 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
285 mono_domain_unlock (domain
);
287 if (user_data
.method
) {
288 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
289 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
294 g_print ("No method at %p\n", ip
);
298 method
= mono_method_full_name (jinfo_get_method (ji
), TRUE
);
299 source
= mono_debug_lookup_source_location (jinfo_get_method (ji
), (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), target_domain
);
301 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
304 if (gsctx
->is_gsharedvt
)
305 shared_type
= "gsharedvt ";
307 shared_type
= "gshared ";
310 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
);
313 g_print ("%s:%d\n", source
->source_file
, source
->row
);
316 mono_debug_free_source_location (source
);
321 * mono_method_same_domain:
323 * Determine whenever two compiled methods are in the same domain, thus
324 * the address of the callee can be embedded in the caller.
326 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
330 if (!caller
|| caller
->is_trampoline
|| !callee
|| callee
->is_trampoline
)
334 * If the call was made from domain-neutral to domain-specific
335 * code, we can't patch the call site.
337 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
340 cmethod
= jinfo_get_method (caller
);
341 if ((cmethod
->klass
== mono_defaults
.appdomain_class
) &&
342 (strstr (cmethod
->name
, "InvokeInDomain"))) {
343 /* The InvokeInDomain methods change the current appdomain */
351 * mono_global_codeman_reserve:
353 * Allocate code memory from the global code manager.
355 void *(mono_global_codeman_reserve
) (int size
)
360 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
362 if (!global_codeman
) {
363 /* This can happen during startup */
364 global_codeman
= mono_code_manager_new ();
365 return mono_code_manager_reserve (global_codeman
, size
);
369 ptr
= mono_code_manager_reserve (global_codeman
, size
);
375 /* The callback shouldn't take any locks */
377 mono_global_codeman_foreach (MonoCodeManagerFunc func
, void *user_data
)
380 mono_code_manager_foreach (global_codeman
, func
, user_data
);
385 * mono_create_unwind_op:
387 * Create an unwind op with the given parameters.
390 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
392 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
403 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
405 MonoJumpInfoToken
*res
= (MonoJumpInfoToken
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
408 res
->has_context
= context
!= NULL
;
410 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
416 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
418 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
422 * mono_tramp_info_create:
424 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
425 * of JI, and UNWIND_OPS.
428 mono_tramp_info_create (const char *name
, guint8
*code
, guint32 code_size
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
430 MonoTrampInfo
*info
= g_new0 (MonoTrampInfo
, 1);
432 info
->name
= g_strdup (name
);
434 info
->code_size
= code_size
;
436 info
->unwind_ops
= unwind_ops
;
442 mono_tramp_info_free (MonoTrampInfo
*info
)
447 mono_free_unwind_info (info
->unwind_ops
);
448 if (info
->owns_uw_info
)
449 g_free (info
->uw_info
);
454 register_trampoline_jit_info (MonoDomain
*domain
, MonoTrampInfo
*info
)
458 ji
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, mono_jit_info_size ((MonoJitInfoFlags
)0, 0, 0));
459 mono_jit_info_init (ji
, NULL
, info
->code
, info
->code_size
, (MonoJitInfoFlags
)0, 0, 0);
460 ji
->d
.tramp_info
= info
;
461 ji
->is_trampoline
= TRUE
;
463 ji
->unwind_info
= mono_cache_unwind_info (info
->uw_info
, info
->uw_info_len
);
465 mono_jit_info_table_add (domain
, ji
);
469 * mono_tramp_info_register:
471 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
476 mono_tramp_info_register_internal (MonoTrampInfo
*info
, MonoDomain
*domain
, gboolean aot
)
484 domain
= mono_get_root_domain ();
487 copy
= mono_domain_alloc0 (domain
, sizeof (MonoTrampInfo
));
489 copy
= g_new0 (MonoTrampInfo
, 1);
491 copy
->code
= info
->code
;
492 copy
->code_size
= info
->code_size
;
493 copy
->name
= g_strdup (info
->name
);
495 if (info
->unwind_ops
) {
496 copy
->uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, ©
->uw_info_len
);
497 copy
->owns_uw_info
= TRUE
;
499 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
500 guint8
*temp
= copy
->uw_info
;
501 copy
->uw_info
= mono_domain_alloc (domain
, copy
->uw_info_len
);
502 memcpy (copy
->uw_info
, temp
, copy
->uw_info_len
);
506 /* Trampolines from aot have the unwind ops already encoded */
507 copy
->uw_info
= info
->uw_info
;
508 copy
->uw_info_len
= info
->uw_info_len
;
511 mono_save_trampoline_xdebug_info (info
);
512 mono_lldb_save_trampoline_info (info
);
514 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
516 mono_arch_unwindinfo_install_tramp_unwind_info (info
->unwind_ops
, info
->code
, info
->code_size
);
520 /* If no root domain has been created yet, postpone the registration. */
522 tramp_infos
= g_slist_prepend (tramp_infos
, copy
);
524 } else if (copy
->uw_info
) {
525 /* Only register trampolines that have unwind infos */
526 register_trampoline_jit_info (domain
, copy
);
529 if (mono_jit_map_is_enabled ())
530 mono_emit_jit_tramp (info
->code
, info
->code_size
, info
->name
);
532 mono_tramp_info_free (info
);
536 mono_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
538 mono_tramp_info_register_internal (info
, domain
, FALSE
);
542 mono_aot_tramp_info_register (MonoTrampInfo
*info
, MonoDomain
*domain
)
544 mono_tramp_info_register_internal (info
, domain
, TRUE
);
548 mono_tramp_info_cleanup (void)
552 for (l
= tramp_infos
; l
; l
= l
->next
) {
553 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
555 mono_tramp_info_free (info
);
557 g_slist_free (tramp_infos
);
560 /* Register trampolines created before the root domain was created in the jit info tables */
562 register_trampolines (MonoDomain
*domain
)
566 for (l
= tramp_infos
; l
; l
= l
->next
) {
567 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
569 register_trampoline_jit_info (domain
, info
);
573 G_GNUC_UNUSED
static void
579 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
580 * Set a breakpoint in break_count () to break the last time <x> is done.
582 G_GNUC_UNUSED gboolean
583 mono_debug_count (void)
585 static int count
= 0, int_val
= 0;
586 static gboolean inited
, has_value
= FALSE
;
591 char *value
= g_getenv ("COUNT");
593 int_val
= atoi (value
);
603 if (count
== int_val
)
613 mono_icall_get_wrapper_method (MonoJitICallInfo
* callinfo
)
616 gboolean check_exc
= TRUE
;
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
);
631 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
635 gconstpointer trampoline
;
636 MonoDomain
*domain
= mono_get_root_domain ();
638 if (callinfo
->wrapper
)
639 return callinfo
->wrapper
;
641 if (callinfo
->trampoline
)
642 return callinfo
->trampoline
;
644 wrapper
= mono_icall_get_wrapper_method (callinfo
);
647 trampoline
= mono_compile_method_checked (wrapper
, error
);
648 mono_error_assert_ok (error
);
650 trampoline
= mono_create_jit_trampoline (domain
, wrapper
, error
);
651 mono_error_assert_ok (error
);
652 trampoline
= mono_create_ftnptr (domain
, (gpointer
)trampoline
);
656 if (!callinfo
->trampoline
) {
657 mono_register_jit_icall_wrapper (callinfo
, trampoline
);
658 callinfo
->trampoline
= trampoline
;
660 mono_loader_unlock ();
662 return callinfo
->trampoline
;
666 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
668 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
671 static MonoJitDynamicMethodInfo
*
672 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
674 MonoJitDynamicMethodInfo
*res
;
676 if (domain_jit_info (domain
)->dynamic_code_hash
)
677 res
= (MonoJitDynamicMethodInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
684 template <typename T
>
686 register_opcode_emulation (int opcode
, const char *name
, const char *sigstr
, T func
, const char *symbol
, gboolean no_wrapper
)
689 register_opcode_emulation (int opcode
, const char *name
, const char *sigstr
, gpointer func
, const char *symbol
, gboolean no_wrapper
)
693 mini_register_opcode_emulation (opcode
, name
, sigstr
, func
, symbol
, no_wrapper
);
695 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
697 g_assert (!sig
->hasthis
);
698 g_assert (sig
->param_count
< 3);
700 mono_register_jit_icall_full (func
, name
, sig
, no_wrapper
, symbol
);
705 * For JIT icalls implemented in C.
706 * NAME should be the same as the name of the C function whose address is FUNC.
707 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
708 * can't throw exceptions.
711 template <typename T
>
713 register_icall (T func
, const char *name
, const char *sigstr
, gboolean avoid_wrapper
)
716 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean avoid_wrapper
)
719 MonoMethodSignature
*sig
;
722 sig
= mono_create_icall_signature (sigstr
);
726 mono_register_jit_icall_full (func
, name
, sig
, avoid_wrapper
, name
);
730 template <typename T
>
732 register_icall_no_wrapper (T func
, const char *name
, const char *sigstr
)
735 register_icall_no_wrapper (gpointer func
, const char *name
, const char *sigstr
)
738 MonoMethodSignature
*sig
;
741 sig
= mono_create_icall_signature (sigstr
);
745 mono_register_jit_icall_full (func
, name
, sig
, TRUE
, name
);
749 template <typename T
>
751 register_icall_with_wrapper (T func
, const char *name
, const char *sigstr
)
754 register_icall_with_wrapper (gpointer func
, const char *name
, const char *sigstr
)
757 MonoMethodSignature
*sig
;
760 sig
= mono_create_icall_signature (sigstr
);
764 mono_register_jit_icall_full (func
, name
, sig
, FALSE
, name
);
768 * Register an icall where FUNC is dynamically generated or otherwise not
769 * possible to link to it using NAME during AOT.
772 template <typename T
>
774 register_dyn_icall (T func
, const char *name
, const char *sigstr
, gboolean save
)
777 register_dyn_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
780 MonoMethodSignature
*sig
;
783 sig
= mono_create_icall_signature (sigstr
);
787 mono_register_jit_icall (func
, name
, sig
, save
);
793 MonoJitTlsData
*jit_tls
;
795 if ((jit_tls
= mono_tls_get_jit_tls ()))
798 * We do not assert here because this function can be called from
799 * mini-gc.c on a thread that has not executed any managed code, yet
800 * (the thread object allocation can trigger a collection).
806 mono_set_lmf (MonoLMF
*lmf
)
808 (*mono_get_lmf_addr ()) = lmf
;
812 mono_set_jit_tls (MonoJitTlsData
*jit_tls
)
814 MonoThreadInfo
*info
;
816 mono_tls_set_jit_tls (jit_tls
);
818 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
819 info
= mono_thread_info_current ();
821 mono_thread_info_tls_set (info
, TLS_KEY_JIT_TLS
, jit_tls
);
825 mono_set_lmf_addr (MonoLMF
**lmf_addr
)
827 MonoThreadInfo
*info
;
829 mono_tls_set_lmf_addr (lmf_addr
);
831 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
832 info
= mono_thread_info_current ();
834 mono_thread_info_tls_set (info
, TLS_KEY_LMF_ADDR
, lmf_addr
);
840 * Push an MonoLMFExt frame on the LMF stack.
843 mono_push_lmf (MonoLMFExt
*ext
)
847 lmf_addr
= mono_get_lmf_addr ();
849 ext
->lmf
.previous_lmf
= *lmf_addr
;
850 /* Mark that this is a MonoLMFExt */
851 ext
->lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
->lmf
.previous_lmf
) | 2);
853 mono_set_lmf ((MonoLMF
*)ext
);
859 * Pop the last frame from the LMF stack.
862 mono_pop_lmf (MonoLMF
*lmf
)
864 mono_set_lmf ((MonoLMF
*)(((gssize
)lmf
->previous_lmf
) & ~3));
868 * mono_jit_thread_attach:
870 * Called by Xamarin.Mac and other products. Attach thread to runtime if
871 * needed and switch to @domain.
873 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
875 * If the thread is newly-attached, put into GC Safe mode.
877 * @return the original domain which needs to be restored, or NULL.
880 mono_jit_thread_attach (MonoDomain
*domain
)
886 /* Happens when called from AOTed code which is only used in the root domain. */
887 domain
= mono_get_root_domain ();
892 attached
= mono_tls_get_jit_tls () != NULL
;
895 mono_thread_attach (domain
);
898 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
900 /* mono_jit_thread_attach is external-only and not called by
901 * the runtime on any of our own threads. So if we get here,
902 * the thread is running native code - leave it in GC Safe mode
903 * and leave it to the n2m invoke wrappers or MONO_API entry
904 * points to switch to GC Unsafe.
906 MONO_STACKDATA (stackdata
);
907 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata
);
910 orig
= mono_domain_get ();
912 mono_domain_set (domain
, TRUE
);
914 return orig
!= domain
? orig
: NULL
;
918 * mono_jit_set_domain:
920 * Set domain to @domain if @domain is not null
923 mono_jit_set_domain (MonoDomain
*domain
)
925 g_assert (!mono_threads_is_blocking_transition_enabled ());
928 mono_domain_set (domain
, TRUE
);
933 * \param obj exception object
934 * Abort the thread, print exception information and stack trace
937 mono_thread_abort (MonoObject
*obj
)
939 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
941 /* handle_remove should be eventually called for this thread, too
944 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
945 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
) ||
946 ((obj
->vtable
->klass
) == mono_class_get_appdomain_unloaded_exception_class () &&
947 mono_thread_info_current ()->runtime_thread
)) {
950 mono_invoke_unhandled_exception_hook (obj
);
954 static MonoJitTlsData
*
955 setup_jit_tls_data (gpointer stack_start
, MonoAbortFunction abort_func
)
957 MonoJitTlsData
*jit_tls
;
960 jit_tls
= mono_tls_get_jit_tls ();
964 jit_tls
= g_new0 (MonoJitTlsData
, 1);
966 jit_tls
->abort_func
= abort_func
;
967 jit_tls
->end_of_stack
= stack_start
;
969 mono_set_jit_tls (jit_tls
);
971 lmf
= g_new0 (MonoLMF
, 1);
972 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
974 jit_tls
->first_lmf
= lmf
;
976 mono_set_lmf_addr (&jit_tls
->lmf
);
980 #ifdef MONO_ARCH_HAVE_TLS_INIT
981 mono_arch_tls_init ();
984 mono_setup_altstack (jit_tls
);
990 free_jit_tls_data (MonoJitTlsData
*jit_tls
)
992 //This happens during AOT cuz the thread is never attached
995 mono_arch_free_jit_tls_data (jit_tls
);
996 mono_free_altstack (jit_tls
);
998 g_free (jit_tls
->first_lmf
);
999 g_free (jit_tls
->interp_context
);
1004 mono_thread_start_cb (intptr_t tid
, gpointer stack_start
, gpointer func
)
1006 MonoThreadInfo
*thread
;
1007 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
1008 thread
= mono_thread_info_current_unchecked ();
1010 thread
->jit_data
= jit_tls
;
1012 mono_arch_cpu_init ();
1015 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
1018 mono_thread_abort_dummy (MonoObject
*obj
)
1020 if (mono_thread_attach_aborted_cb
)
1021 mono_thread_attach_aborted_cb (obj
);
1023 mono_thread_abort (obj
);
1027 mono_thread_attach_cb (intptr_t tid
, gpointer stack_start
)
1029 MonoThreadInfo
*thread
;
1030 MonoJitTlsData
*jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
1031 thread
= mono_thread_info_current_unchecked ();
1033 thread
->jit_data
= jit_tls
;
1035 mono_arch_cpu_init ();
1039 mini_thread_cleanup (MonoNativeThreadId tid
)
1041 MonoJitTlsData
*jit_tls
= NULL
;
1042 MonoThreadInfo
*info
;
1044 info
= mono_thread_info_current_unchecked ();
1046 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1047 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1048 * not a trivial thing.
1050 * The current offender is mono_thread_manage which cleanup threads from the outside.
1052 if (info
&& mono_thread_info_get_tid (info
) == tid
) {
1053 jit_tls
= info
->jit_data
;
1054 info
->jit_data
= NULL
;
1056 mono_set_jit_tls (NULL
);
1058 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1059 if (mono_get_lmf ()) {
1060 mono_set_lmf (NULL
);
1061 mono_set_lmf_addr (NULL
);
1064 info
= mono_thread_info_lookup (tid
);
1066 jit_tls
= info
->jit_data
;
1067 info
->jit_data
= NULL
;
1069 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1073 free_jit_tls_data (jit_tls
);
1077 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
1079 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
1083 ji
->data
.target
= target
;
1089 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1091 static const char* const patch_info_str
[] = {
1092 #define PATCH_INFO(a,b) "" #a,
1093 #include "patch-info.h"
1098 mono_ji_type_to_string (MonoJumpInfoType type
)
1100 return patch_info_str
[type
];
1104 mono_print_ji (const MonoJumpInfo
*ji
)
1107 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1108 MonoJumpInfoRgctxEntry
*entry
= ji
->data
.rgctx_entry
;
1110 printf ("[RGCTX_FETCH ");
1111 mono_print_ji (entry
->data
);
1112 printf (" - %s]", mono_rgctx_info_type_to_str (entry
->info_type
));
1115 case MONO_PATCH_INFO_METHODCONST
: {
1116 char *s
= mono_method_full_name (ji
->data
.method
, TRUE
);
1117 printf ("[METHODCONST - %s]", s
);
1121 case MONO_PATCH_INFO_JIT_ICALL
: {
1122 printf ("[JIT_ICALL - %s]", ji
->data
.name
);
1125 case MONO_PATCH_INFO_CLASS
: {
1126 char *name
= mono_class_full_name (ji
->data
.klass
);
1127 printf ("[CLASS - %s]", name
);
1132 printf ("[%s]", patch_info_str
[ji
->type
]);
1140 mono_ji_type_to_string (MonoJumpInfoType type
)
1146 mono_print_ji (const MonoJumpInfo
*ji
)
1153 * mono_patch_info_dup_mp:
1155 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1158 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
1160 MonoJumpInfo
*res
= (MonoJumpInfo
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
1161 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
1163 switch (patch_info
->type
) {
1164 case MONO_PATCH_INFO_RVA
:
1165 case MONO_PATCH_INFO_LDSTR
:
1166 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1167 case MONO_PATCH_INFO_LDTOKEN
:
1168 case MONO_PATCH_INFO_DECLSEC
:
1169 res
->data
.token
= (MonoJumpInfoToken
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
1170 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
1172 case MONO_PATCH_INFO_SWITCH
:
1173 res
->data
.table
= (MonoJumpInfoBBTable
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
1174 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
1175 res
->data
.table
->table
= (MonoBasicBlock
**)mono_mempool_alloc (mp
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1176 memcpy (res
->data
.table
->table
, patch_info
->data
.table
->table
, sizeof (MonoBasicBlock
*) * patch_info
->data
.table
->table_size
);
1178 case MONO_PATCH_INFO_RGCTX_FETCH
:
1179 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
:
1180 res
->data
.rgctx_entry
= (MonoJumpInfoRgctxEntry
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
1181 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
1182 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
1184 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1185 res
->data
.del_tramp
= (MonoDelegateClassMethodPair
*)mono_mempool_alloc0 (mp
, sizeof (MonoDelegateClassMethodPair
));
1186 memcpy (res
->data
.del_tramp
, patch_info
->data
.del_tramp
, sizeof (MonoDelegateClassMethodPair
));
1188 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1189 res
->data
.gsharedvt
= (MonoJumpInfoGSharedVtCall
*)mono_mempool_alloc (mp
, sizeof (MonoJumpInfoGSharedVtCall
));
1190 memcpy (res
->data
.gsharedvt
, patch_info
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
1192 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
1193 MonoGSharedVtMethodInfo
*info
;
1194 MonoGSharedVtMethodInfo
*oinfo
;
1197 oinfo
= patch_info
->data
.gsharedvt_method
;
1198 info
= (MonoGSharedVtMethodInfo
*)mono_mempool_alloc (mp
, sizeof (MonoGSharedVtMethodInfo
));
1199 res
->data
.gsharedvt_method
= info
;
1200 memcpy (info
, oinfo
, sizeof (MonoGSharedVtMethodInfo
));
1201 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_mempool_alloc (mp
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->count_entries
);
1202 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
1203 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
1204 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
1206 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
1208 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1209 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1212 case MONO_PATCH_INFO_VIRT_METHOD
: {
1213 MonoJumpInfoVirtMethod
*info
;
1214 MonoJumpInfoVirtMethod
*oinfo
;
1216 oinfo
= patch_info
->data
.virt_method
;
1217 info
= (MonoJumpInfoVirtMethod
*)mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoVirtMethod
));
1218 res
->data
.virt_method
= info
;
1219 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
1230 mono_patch_info_hash (gconstpointer data
)
1232 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
1235 case MONO_PATCH_INFO_RVA
:
1236 case MONO_PATCH_INFO_LDSTR
:
1237 case MONO_PATCH_INFO_LDTOKEN
:
1238 case MONO_PATCH_INFO_DECLSEC
:
1239 return (ji
->type
<< 8) | ji
->data
.token
->token
;
1240 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1241 return (ji
->type
<< 8) | ji
->data
.token
->token
| (ji
->data
.token
->has_context
? (gsize
)ji
->data
.token
->context
.class_inst
: 0);
1242 case MONO_PATCH_INFO_JIT_ICALL
:
1243 return (ji
->type
<< 8) | g_str_hash (ji
->data
.name
);
1244 case MONO_PATCH_INFO_VTABLE
:
1245 case MONO_PATCH_INFO_CLASS
:
1246 case MONO_PATCH_INFO_IID
:
1247 case MONO_PATCH_INFO_ADJUSTED_IID
:
1248 case MONO_PATCH_INFO_METHODCONST
:
1249 case MONO_PATCH_INFO_METHOD
:
1250 case MONO_PATCH_INFO_METHOD_JUMP
:
1251 case MONO_PATCH_INFO_METHOD_FTNDESC
:
1252 case MONO_PATCH_INFO_IMAGE
:
1253 case MONO_PATCH_INFO_ICALL_ADDR
:
1254 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1255 case MONO_PATCH_INFO_FIELD
:
1256 case MONO_PATCH_INFO_SFLDA
:
1257 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1258 case MONO_PATCH_INFO_METHOD_RGCTX
:
1259 case MONO_PATCH_INFO_SIGNATURE
:
1260 case MONO_PATCH_INFO_METHOD_CODE_SLOT
:
1261 case MONO_PATCH_INFO_AOT_JIT_INFO
:
1262 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1263 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1264 return (ji
->type
<< 8) | (gssize
)ji
->data
.target
;
1265 case MONO_PATCH_INFO_GSHAREDVT_CALL
:
1266 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt
->method
;
1267 case MONO_PATCH_INFO_RGCTX_FETCH
:
1268 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1269 MonoJumpInfoRgctxEntry
*e
= ji
->data
.rgctx_entry
;
1271 return (ji
->type
<< 8) | (gssize
)e
->method
| (e
->in_mrgctx
) | e
->info_type
| mono_patch_info_hash (e
->data
);
1273 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1274 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR
:
1275 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
:
1276 case MONO_PATCH_INFO_GC_NURSERY_START
:
1277 case MONO_PATCH_INFO_GC_NURSERY_BITS
:
1278 case MONO_PATCH_INFO_GOT_OFFSET
:
1279 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1280 case MONO_PATCH_INFO_AOT_MODULE
:
1281 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
:
1282 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
:
1283 return (ji
->type
<< 8);
1284 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1285 return (ji
->type
<< 8) | (ji
->data
.index
);
1286 case MONO_PATCH_INFO_SWITCH
:
1287 return (ji
->type
<< 8) | ji
->data
.table
->table_size
;
1288 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1289 return (ji
->type
<< 8) | (gssize
)ji
->data
.gsharedvt_method
->method
;
1290 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
:
1291 /* Hash on the selector name */
1292 return g_str_hash (ji
->data
.target
);
1293 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1294 return (ji
->type
<< 8) | (gsize
)ji
->data
.del_tramp
->klass
| (gsize
)ji
->data
.del_tramp
->method
| (gsize
)ji
->data
.del_tramp
->is_virtual
;
1295 case MONO_PATCH_INFO_LDSTR_LIT
:
1296 return g_str_hash (ji
->data
.target
);
1297 case MONO_PATCH_INFO_VIRT_METHOD
: {
1298 MonoJumpInfoVirtMethod
*info
= ji
->data
.virt_method
;
1300 return (ji
->type
<< 8) | (gssize
)info
->klass
| (gssize
)info
->method
;
1302 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1303 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1304 return (ji
->type
<< 8) | g_str_hash (ji
->data
.target
);
1305 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1306 return (ji
->type
<< 8) | mono_signature_hash (ji
->data
.sig
);
1308 printf ("info type: %d\n", ji
->type
);
1309 mono_print_ji (ji
); printf ("\n");
1310 g_assert_not_reached ();
1316 * mono_patch_info_equal:
1318 * This might fail to recognize equivalent patches, i.e. floats, so its only
1319 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1323 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
1325 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
1326 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
1328 if (ji1
->type
!= ji2
->type
)
1331 switch (ji1
->type
) {
1332 case MONO_PATCH_INFO_RVA
:
1333 case MONO_PATCH_INFO_LDSTR
:
1334 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1335 case MONO_PATCH_INFO_LDTOKEN
:
1336 case MONO_PATCH_INFO_DECLSEC
:
1337 if ((ji1
->data
.token
->image
!= ji2
->data
.token
->image
) ||
1338 (ji1
->data
.token
->token
!= ji2
->data
.token
->token
) ||
1339 (ji1
->data
.token
->has_context
!= ji2
->data
.token
->has_context
) ||
1340 (ji1
->data
.token
->context
.class_inst
!= ji2
->data
.token
->context
.class_inst
) ||
1341 (ji1
->data
.token
->context
.method_inst
!= ji2
->data
.token
->context
.method_inst
))
1344 case MONO_PATCH_INFO_JIT_ICALL
:
1345 return g_str_equal (ji1
->data
.name
, ji2
->data
.name
);
1346 case MONO_PATCH_INFO_RGCTX_FETCH
:
1347 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1348 MonoJumpInfoRgctxEntry
*e1
= ji1
->data
.rgctx_entry
;
1349 MonoJumpInfoRgctxEntry
*e2
= ji2
->data
.rgctx_entry
;
1351 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
);
1353 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
1354 MonoJumpInfoGSharedVtCall
*c1
= ji1
->data
.gsharedvt
;
1355 MonoJumpInfoGSharedVtCall
*c2
= ji2
->data
.gsharedvt
;
1357 return c1
->sig
== c2
->sig
&& c1
->method
== c2
->method
;
1359 case MONO_PATCH_INFO_GSHAREDVT_METHOD
:
1360 return ji1
->data
.gsharedvt_method
->method
== ji2
->data
.gsharedvt_method
->method
;
1361 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1362 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
;
1363 case MONO_PATCH_INFO_CASTCLASS_CACHE
:
1364 return ji1
->data
.index
== ji2
->data
.index
;
1365 case MONO_PATCH_INFO_VIRT_METHOD
:
1366 return ji1
->data
.virt_method
->klass
== ji2
->data
.virt_method
->klass
&& ji1
->data
.virt_method
->method
== ji2
->data
.virt_method
->method
;
1367 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1368 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
:
1369 if (ji1
->data
.target
== ji2
->data
.target
)
1371 return strcmp ((const char*)ji1
->data
.target
, (const char*)ji2
->data
.target
) == 0 ? 1 : 0;
1372 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1373 return mono_metadata_signature_equal (ji1
->data
.sig
, ji2
->data
.sig
) ? 1 : 0;
1375 if (ji1
->data
.target
!= ji2
->data
.target
)
1384 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
, MonoError
*error
)
1386 unsigned char *ip
= patch_info
->ip
.i
+ code
;
1387 gconstpointer target
= NULL
;
1391 switch (patch_info
->type
) {
1392 case MONO_PATCH_INFO_BB
:
1394 * FIXME: This could be hit for methods without a prolog. Should use -1
1395 * but too much code depends on a 0 initial value.
1397 //g_assert (patch_info->data.bb->native_offset);
1398 target
= patch_info
->data
.bb
->native_offset
+ code
;
1400 case MONO_PATCH_INFO_ABS
:
1401 target
= patch_info
->data
.target
;
1403 case MONO_PATCH_INFO_LABEL
:
1404 target
= patch_info
->data
.inst
->inst_c0
+ code
;
1406 case MONO_PATCH_INFO_IP
:
1409 case MONO_PATCH_INFO_METHOD_REL
:
1410 target
= code
+ patch_info
->data
.offset
;
1412 case MONO_PATCH_INFO_JIT_ICALL
: {
1413 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1415 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL %s", patch_info
->data
.name
);
1416 g_assert_not_reached ();
1418 target
= mono_icall_get_wrapper (mi
);
1421 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1422 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL
: {
1423 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
1425 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info
->data
.name
);
1426 g_assert_not_reached ();
1431 case MONO_PATCH_INFO_METHOD_JUMP
:
1432 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
, error
);
1433 if (!mono_error_ok (error
))
1436 case MONO_PATCH_INFO_METHOD
:
1437 if (patch_info
->data
.method
== method
) {
1440 /* get the trampoline to the method from the domain */
1441 target
= mono_create_jit_trampoline (domain
, patch_info
->data
.method
, error
);
1442 if (!mono_error_ok (error
))
1446 case MONO_PATCH_INFO_METHOD_FTNDESC
: {
1448 * Return an ftndesc for either AOTed code, or for an interp entry.
1450 target
= mini_llvmonly_load_method_ftndesc (patch_info
->data
.method
, FALSE
, FALSE
, error
);
1451 return_val_if_nok (error
, NULL
);
1454 case MONO_PATCH_INFO_METHOD_CODE_SLOT
: {
1457 mono_domain_lock (domain
);
1458 if (!domain_jit_info (domain
)->method_code_hash
)
1459 domain_jit_info (domain
)->method_code_hash
= g_hash_table_new (NULL
, NULL
);
1460 code_slot
= g_hash_table_lookup (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
);
1462 code_slot
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1463 g_hash_table_insert (domain_jit_info (domain
)->method_code_hash
, patch_info
->data
.method
, code_slot
);
1465 mono_domain_unlock (domain
);
1469 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG
:
1470 target
= (gpointer
)&mono_polling_required
;
1472 case MONO_PATCH_INFO_SWITCH
: {
1473 gpointer
*jump_table
;
1475 if (method
&& method
->dynamic
) {
1476 jump_table
= (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1478 if (mono_aot_only
) {
1479 jump_table
= (void **)mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1481 jump_table
= (void **)mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
1485 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
1486 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
1489 target
= jump_table
;
1492 case MONO_PATCH_INFO_METHODCONST
:
1493 case MONO_PATCH_INFO_CLASS
:
1494 case MONO_PATCH_INFO_IMAGE
:
1495 case MONO_PATCH_INFO_FIELD
:
1496 case MONO_PATCH_INFO_SIGNATURE
:
1497 case MONO_PATCH_INFO_AOT_MODULE
:
1498 target
= patch_info
->data
.target
;
1500 case MONO_PATCH_INFO_IID
:
1501 mono_class_init_internal (patch_info
->data
.klass
);
1502 target
= GUINT_TO_POINTER (m_class_get_interface_id (patch_info
->data
.klass
));
1504 case MONO_PATCH_INFO_ADJUSTED_IID
:
1505 mono_class_init_internal (patch_info
->data
.klass
);
1506 target
= GUINT_TO_POINTER ((guint32
)(-((m_class_get_interface_id (patch_info
->data
.klass
) + 1) * TARGET_SIZEOF_VOID_P
)));
1508 case MONO_PATCH_INFO_VTABLE
:
1509 target
= mono_class_vtable_checked (domain
, patch_info
->data
.klass
, error
);
1510 mono_error_assert_ok (error
);
1512 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
1513 MonoDelegateClassMethodPair
*del_tramp
= patch_info
->data
.del_tramp
;
1515 if (del_tramp
->is_virtual
)
1516 target
= mono_create_delegate_virtual_trampoline (domain
, del_tramp
->klass
, del_tramp
->method
);
1518 target
= mono_create_delegate_trampoline_info (domain
, del_tramp
->klass
, del_tramp
->method
);
1521 case MONO_PATCH_INFO_SFLDA
: {
1522 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, patch_info
->data
.field
->parent
, error
);
1523 mono_error_assert_ok (error
);
1525 if (mono_class_field_is_special_static (patch_info
->data
.field
)) {
1526 gpointer addr
= NULL
;
1528 mono_domain_lock (domain
);
1529 if (domain
->special_static_fields
)
1530 addr
= g_hash_table_lookup (domain
->special_static_fields
, patch_info
->data
.field
);
1531 mono_domain_unlock (domain
);
1536 if (!vtable
->initialized
&& !mono_class_is_before_field_init (vtable
->klass
) && (method
&& mono_class_needs_cctor_run (vtable
->klass
, method
)))
1537 /* Done by the generated code */
1541 if (!mono_runtime_class_init_full (vtable
, error
)) {
1546 target
= (char*)mono_vtable_get_static_field_data (vtable
) + patch_info
->data
.field
->offset
;
1549 case MONO_PATCH_INFO_RVA
: {
1550 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
1553 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
1554 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
1557 case MONO_PATCH_INFO_R4
:
1558 case MONO_PATCH_INFO_R8
:
1559 target
= patch_info
->data
.target
;
1561 case MONO_PATCH_INFO_EXC_NAME
:
1562 target
= patch_info
->data
.name
;
1564 case MONO_PATCH_INFO_LDSTR
:
1566 mono_ldstr_checked (domain
, patch_info
->data
.token
->image
,
1567 mono_metadata_token_index (patch_info
->data
.token
->token
), error
);
1569 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
1571 MonoClass
*handle_class
;
1573 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1574 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1575 if (!mono_error_ok (error
))
1577 mono_class_init_internal (handle_class
);
1578 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType
*)handle
));
1580 target
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
1581 if (!mono_error_ok (error
))
1585 case MONO_PATCH_INFO_LDTOKEN
: {
1587 MonoClass
*handle_class
;
1589 handle
= mono_ldtoken_checked (patch_info
->data
.token
->image
,
1590 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
, error
);
1591 mono_error_assert_msg_ok (error
, "Could not patch ldtoken");
1592 mono_class_init_internal (handle_class
);
1597 case MONO_PATCH_INFO_DECLSEC
:
1598 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
1600 case MONO_PATCH_INFO_ICALL_ADDR
:
1601 case MONO_PATCH_INFO_ICALL_ADDR_CALL
:
1602 /* run_cctors == 0 -> AOT */
1603 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
1604 const char *exc_class
;
1605 const char *exc_arg
;
1608 target
= mono_lookup_pinvoke_call (patch_info
->data
.method
, &exc_class
, &exc_arg
);
1610 if (mono_aot_only
) {
1611 mono_error_set_exception_instance (error
, mono_exception_from_name_msg (mono_defaults
.corlib
, "System", exc_class
, exc_arg
));
1614 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
));
1620 target
= mono_lookup_internal_call (patch_info
->data
.method
);
1622 if (!target
&& run_cctors
)
1623 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
1626 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1627 target
= mono_thread_interruption_request_flag ();
1629 case MONO_PATCH_INFO_METHOD_RGCTX
:
1630 target
= mini_method_get_rgctx (patch_info
->data
.method
);
1632 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX
: {
1633 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1635 target
= GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot
));
1638 case MONO_PATCH_INFO_BB_OVF
:
1639 case MONO_PATCH_INFO_EXC_OVF
:
1640 case MONO_PATCH_INFO_GOT_OFFSET
:
1641 case MONO_PATCH_INFO_NONE
:
1643 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1644 int slot
= mini_get_rgctx_entry_slot (patch_info
->data
.rgctx_entry
);
1646 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
1649 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1650 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
1652 /* AOT, not needed */
1655 target
= mono_arch_get_seq_point_info (domain
, code
);
1658 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR
: {
1659 int card_table_shift_bits
;
1660 gpointer card_table_mask
;
1662 target
= mono_gc_get_card_table (&card_table_shift_bits
, &card_table_mask
);
1665 case MONO_PATCH_INFO_GC_NURSERY_START
: {
1669 target
= mono_gc_get_nursery (&shift_bits
, &size
);
1672 case MONO_PATCH_INFO_GC_NURSERY_BITS
: {
1676 mono_gc_get_nursery (&shift_bits
, &size
);
1678 target
= (gpointer
)(gssize
)shift_bits
;
1681 case MONO_PATCH_INFO_CASTCLASS_CACHE
: {
1682 target
= mono_domain_alloc0 (domain
, sizeof (gpointer
));
1685 case MONO_PATCH_INFO_OBJC_SELECTOR_REF
: {
1689 case MONO_PATCH_INFO_LDSTR_LIT
: {
1693 len
= strlen ((const char *)patch_info
->data
.target
);
1694 s
= (char *)mono_domain_alloc0 (domain
, len
+ 1);
1695 memcpy (s
, patch_info
->data
.target
, len
);
1700 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER
:
1701 target
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, patch_info
->data
.sig
, NULL
, -1, FALSE
);
1703 case MONO_PATCH_INFO_GET_TLS_TRAMP
:
1704 target
= mono_tls_get_tls_getter ((MonoTlsKey
)patch_info
->data
.index
, FALSE
);
1706 case MONO_PATCH_INFO_SET_TLS_TRAMP
:
1707 target
= mono_tls_get_tls_setter ((MonoTlsKey
)patch_info
->data
.index
, FALSE
);
1709 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT
: {
1710 target
= (gpointer
) &mono_profiler_state
.gc_allocation_count
;
1713 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT
: {
1714 target
= (gpointer
) &mono_profiler_state
.exception_clause_count
;
1718 g_assert_not_reached ();
1721 return (gpointer
)target
;
1725 * mini_register_jump_site:
1727 * Register IP as a jump/tailcall site which calls METHOD.
1728 * This is needed because common_call_trampoline () cannot patch
1729 * the call site because the caller ip is not available for jumps.
1732 mini_register_jump_site (MonoDomain
*domain
, MonoMethod
*method
, gpointer ip
)
1734 MonoJumpList
*jlist
;
1736 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1737 method
= shared_method
? shared_method
: method
;
1739 mono_domain_lock (domain
);
1740 jlist
= (MonoJumpList
*)g_hash_table_lookup (domain_jit_info (domain
)->jump_target_hash
, method
);
1742 jlist
= (MonoJumpList
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpList
));
1743 g_hash_table_insert (domain_jit_info (domain
)->jump_target_hash
, method
, jlist
);
1745 jlist
->list
= g_slist_prepend (jlist
->list
, ip
);
1746 mono_domain_unlock (domain
);
1750 * mini_patch_jump_sites:
1752 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1755 mini_patch_jump_sites (MonoDomain
*domain
, MonoMethod
*method
, gpointer addr
)
1757 GHashTable
*hash
= domain_jit_info (domain
)->jump_target_hash
;
1762 MonoJumpInfo patch_info
;
1763 MonoJumpList
*jlist
;
1766 /* The caller/callee might use different instantiations */
1767 MonoMethod
*shared_method
= mini_method_to_shared (method
);
1768 method
= shared_method
? shared_method
: method
;
1770 mono_domain_lock (domain
);
1771 jlist
= (MonoJumpList
*)g_hash_table_lookup (hash
, method
);
1773 g_hash_table_remove (hash
, method
);
1774 mono_domain_unlock (domain
);
1776 patch_info
.next
= NULL
;
1777 patch_info
.ip
.i
= 0;
1778 patch_info
.type
= MONO_PATCH_INFO_METHOD_JUMP
;
1779 patch_info
.data
.method
= method
;
1781 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1782 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
)
1783 mono_arch_patch_code_new (NULL
, domain
, (guint8
*)tmp
->data
, &patch_info
, addr
);
1785 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1786 // for gshared methods
1787 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
1789 mono_arch_patch_code (NULL
, NULL
, domain
, tmp
->data
, &patch_info
, TRUE
, error
);
1790 mono_error_assert_ok (error
);
1797 mini_init_gsctx (MonoDomain
*domain
, MonoMemPool
*mp
, MonoGenericContext
*context
, MonoGenericSharingContext
*gsctx
)
1799 MonoGenericInst
*inst
;
1802 memset (gsctx
, 0, sizeof (MonoGenericSharingContext
));
1804 if (context
&& context
->class_inst
) {
1805 inst
= context
->class_inst
;
1806 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1807 MonoType
*type
= inst
->type_argv
[i
];
1809 if (mini_is_gsharedvt_gparam (type
))
1810 gsctx
->is_gsharedvt
= TRUE
;
1813 if (context
&& context
->method_inst
) {
1814 inst
= context
->method_inst
;
1816 for (i
= 0; i
< inst
->type_argc
; ++i
) {
1817 MonoType
*type
= inst
->type_argv
[i
];
1819 if (mini_is_gsharedvt_gparam (type
))
1820 gsctx
->is_gsharedvt
= TRUE
;
1826 * LOCKING: Acquires the jit code hash lock.
1829 mini_lookup_method (MonoDomain
*domain
, MonoMethod
*method
, MonoMethod
*shared
)
1832 static gboolean inited
= FALSE
;
1833 static int lookups
= 0;
1834 static int failed_lookups
= 0;
1836 mono_domain_jit_code_hash_lock (domain
);
1837 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
1838 if (!ji
&& shared
) {
1839 /* Try generic sharing */
1840 ji
= (MonoJitInfo
*)mono_internal_hash_table_lookup (&domain
->jit_code_hash
, shared
);
1841 if (ji
&& !ji
->has_generic_jit_info
)
1844 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &lookups
);
1845 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT
|MONO_COUNTER_GENERICS
, &failed_lookups
);
1853 mono_domain_jit_code_hash_unlock (domain
);
1859 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
1865 ji
= mini_lookup_method (domain
, method
, NULL
);
1868 if (!mono_method_is_generic_sharable (method
, FALSE
))
1870 shared
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
1871 mono_error_assert_ok (error
);
1872 ji
= mini_lookup_method (domain
, method
, shared
);
1879 mini_get_class (MonoMethod
*method
, guint32 token
, MonoGenericContext
*context
)
1884 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1885 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
1887 klass
= mono_class_inflate_generic_class_checked (klass
, context
, error
);
1888 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1891 klass
= mono_class_get_and_inflate_typespec_checked (m_class_get_image (method
->klass
), token
, context
, error
);
1892 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1895 mono_class_init_internal (klass
);
1900 static FILE* perf_map_file
;
1903 mono_enable_jit_map (void)
1905 if (!perf_map_file
) {
1907 g_snprintf (name
, sizeof (name
), "/tmp/perf-%d.map", getpid ());
1909 perf_map_file
= fopen (name
, "w");
1914 mono_emit_jit_tramp (void *start
, int size
, const char *desc
)
1917 fprintf (perf_map_file
, "%llx %x %s\n", (long long unsigned int)(gsize
)start
, size
, desc
);
1921 mono_emit_jit_map (MonoJitInfo
*jinfo
)
1923 if (perf_map_file
) {
1924 char *name
= mono_method_full_name (jinfo_get_method (jinfo
), TRUE
);
1925 mono_emit_jit_tramp (jinfo
->code_start
, jinfo
->code_size
, name
);
1931 mono_jit_map_is_enabled (void)
1933 return perf_map_file
!= NULL
;
1939 no_gsharedvt_in_wrapper (void)
1941 g_assert_not_reached ();
1947 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.
1948 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1949 Dependency management in this case is too complex to justify implementing it.
1951 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1954 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1955 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1956 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1957 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1962 int compilation_count
; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1963 int ref_count
; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1964 int threads_waiting
; /* Number of threads waiting on this job */
1965 gboolean has_cond
; /* True if @cond was initialized */
1966 gboolean done
; /* True if the method finished JIT'ing */
1967 MonoCoopCond cond
; /* Cond sleeping threads wait one */
1968 } JitCompilationEntry
;
1971 GPtrArray
*in_flight_methods
; //JitCompilationEntry*
1973 } JitCompilationData
;
1976 Timeout, in millisecounds, that we wait other threads to finish JITing.
1977 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.
1979 #define MAX_JIT_TIMEOUT_MS 1000
1982 static JitCompilationData compilation_data
;
1983 static int jit_methods_waited
, jit_methods_multiple
, jit_methods_overload
, jit_spurious_wakeups_or_timeouts
;
1986 mini_jit_init_job_control (void)
1988 mono_coop_mutex_init (&compilation_data
.lock
);
1989 compilation_data
.in_flight_methods
= g_ptr_array_new ();
1993 lock_compilation_data (void)
1995 mono_coop_mutex_lock (&compilation_data
.lock
);
1999 unlock_compilation_data (void)
2001 mono_coop_mutex_unlock (&compilation_data
.lock
);
2004 static JitCompilationEntry
*
2005 find_method (MonoMethod
*method
, MonoDomain
*domain
)
2008 for (i
= 0; i
< compilation_data
.in_flight_methods
->len
; ++i
){
2009 JitCompilationEntry
*e
= (JitCompilationEntry
*)compilation_data
.in_flight_methods
->pdata
[i
];
2010 if (e
->method
== method
&& e
->domain
== domain
)
2018 add_current_thread (MonoJitTlsData
*jit_tls
)
2020 ++jit_tls
->active_jit_methods
;
2024 unref_jit_entry (JitCompilationEntry
*entry
)
2027 if (entry
->ref_count
)
2029 if (entry
->has_cond
)
2030 mono_coop_cond_destroy (&entry
->cond
);
2035 * Returns true if this method waited successfully for another thread to JIT it
2038 wait_or_register_method_to_compile (MonoMethod
*method
, MonoDomain
*domain
)
2040 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2041 JitCompilationEntry
*entry
;
2043 static gboolean inited
;
2045 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_waited
);
2046 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_multiple
);
2047 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_methods_overload
);
2048 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT
|MONO_COUNTER_JIT
, &jit_spurious_wakeups_or_timeouts
);
2052 lock_compilation_data ();
2054 if (!(entry
= find_method (method
, domain
))) {
2055 entry
= g_new0 (JitCompilationEntry
, 1);
2056 entry
->method
= method
;
2057 entry
->domain
= domain
;
2058 entry
->compilation_count
= entry
->ref_count
= 1;
2059 g_ptr_array_add (compilation_data
.in_flight_methods
, entry
);
2060 g_assert (find_method (method
, domain
) == entry
);
2061 add_current_thread (jit_tls
);
2063 unlock_compilation_data ();
2065 } else if (jit_tls
->active_jit_methods
> 0 || mono_threads_is_current_thread_in_protected_block ()) {
2066 //We can't suspend the current thread if it's already JITing a method.
2067 //Dependency management is too compilated and we want to get rid of this anyways.
2069 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2070 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2072 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2073 ++entry
->compilation_count
;
2074 ++jit_methods_multiple
;
2075 ++jit_tls
->active_jit_methods
;
2077 unlock_compilation_data ();
2080 ++jit_methods_waited
;
2083 if (!entry
->has_cond
) {
2084 mono_coop_cond_init (&entry
->cond
);
2085 entry
->has_cond
= TRUE
;
2089 ++entry
->threads_waiting
;
2091 g_assert (entry
->has_cond
);
2092 mono_coop_cond_timedwait (&entry
->cond
, &compilation_data
.lock
, MAX_JIT_TIMEOUT_MS
);
2093 --entry
->threads_waiting
;
2096 unref_jit_entry (entry
);
2097 unlock_compilation_data ();
2100 //We hit the timeout or a spurious wakeup, fallback to JITing
2101 g_assert (entry
->ref_count
> 1);
2102 unref_jit_entry (entry
);
2103 ++jit_spurious_wakeups_or_timeouts
;
2105 ++entry
->compilation_count
;
2106 ++jit_methods_multiple
;
2107 ++jit_tls
->active_jit_methods
;
2109 unlock_compilation_data ();
2117 unregister_method_for_compile (MonoMethod
*method
, MonoDomain
*target_domain
)
2119 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2121 lock_compilation_data ();
2123 g_assert (jit_tls
->active_jit_methods
> 0);
2124 --jit_tls
->active_jit_methods
;
2126 JitCompilationEntry
*entry
= find_method (method
, target_domain
);
2127 g_assert (entry
); // It would be weird to fail
2130 if (entry
->threads_waiting
) {
2131 g_assert (entry
->has_cond
);
2132 mono_coop_cond_broadcast (&entry
->cond
);
2135 if (--entry
->compilation_count
== 0) {
2136 g_ptr_array_remove (compilation_data
.in_flight_methods
, entry
);
2137 unref_jit_entry (entry
);
2140 unlock_compilation_data ();
2144 create_jit_info_for_trampoline (MonoMethod
*wrapper
, MonoTrampInfo
*info
)
2146 MonoDomain
*domain
= mono_get_root_domain ();
2151 if (info
->uw_info
) {
2152 uw_info
= info
->uw_info
;
2153 info_len
= info
->uw_info_len
;
2155 uw_info
= mono_unwind_ops_encode (info
->unwind_ops
, &info_len
);
2158 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
);
2159 jinfo
->d
.method
= wrapper
;
2160 jinfo
->code_start
= info
->code
;
2161 jinfo
->code_size
= info
->code_size
;
2162 jinfo
->unwind_info
= mono_cache_unwind_info (uw_info
, info_len
);
2171 compile_special (MonoMethod
*method
, MonoDomain
*target_domain
, MonoError
*error
)
2176 if (mono_llvm_only
) {
2177 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2178 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2180 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
) {
2182 * These wrappers are only created for signatures which are in the program, but
2183 * sometimes we load methods too eagerly and have to create them even if they
2184 * will never be called.
2186 return (gpointer
)no_gsharedvt_in_wrapper
;
2191 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
2192 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
2194 MonoMethodPInvoke
* piinfo
= (MonoMethodPInvoke
*) method
;
2196 if (!piinfo
->addr
) {
2197 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
2198 piinfo
->addr
= mono_lookup_internal_call (method
);
2199 else if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
2201 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
);
2203 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
);
2206 mono_lookup_pinvoke_call (method
, NULL
, NULL
);
2208 nm
= mono_marshal_get_native_wrapper (method
, TRUE
, mono_aot_only
);
2209 gpointer compiled_method
= mono_jit_compile_method_jit_only (nm
, error
);
2210 return_val_if_nok (error
, NULL
);
2211 code
= mono_get_addr_from_ftnptr (compiled_method
);
2212 jinfo
= mono_jit_info_table_find (target_domain
, code
);
2214 jinfo
= mono_jit_info_table_find (mono_domain_get (), code
);
2216 MONO_PROFILER_RAISE (jit_done
, (method
, jinfo
));
2218 } else if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
2219 const char *name
= method
->name
;
2223 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2224 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
2225 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2228 * We need to make sure this wrapper
2229 * is compiled because it might end up
2230 * in an (M)RGCTX if generic sharing
2231 * is enabled, and would be called
2232 * indirectly. If it were a
2233 * trampoline we'd try to patch that
2234 * indirect call, which is not
2237 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper_full (mi
, TRUE
));
2238 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2239 if (mono_llvm_only
) {
2240 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
2241 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2242 return_val_if_nok (error
, NULL
);
2243 return mono_get_addr_from_ftnptr (compiled_ptr
);
2246 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2247 if (mono_use_interpreter
)
2250 return mono_create_delegate_trampoline (target_domain
, method
->klass
);
2251 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
2252 nm
= mono_marshal_get_delegate_begin_invoke (method
);
2253 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2254 return_val_if_nok (error
, NULL
);
2255 return mono_get_addr_from_ftnptr (compiled_ptr
);
2256 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
2257 nm
= mono_marshal_get_delegate_end_invoke (method
);
2258 gpointer compiled_ptr
= mono_jit_compile_method_jit_only (nm
, error
);
2259 return_val_if_nok (error
, NULL
);
2260 return mono_get_addr_from_ftnptr (compiled_ptr
);
2264 full_name
= mono_method_full_name (method
, TRUE
);
2265 mono_error_set_invalid_program (error
, "Unrecognizable runtime implemented method '%s'", full_name
);
2270 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2271 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2273 if (info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
|| info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_OUT
) {
2274 static MonoTrampInfo
*in_tinfo
, *out_tinfo
;
2275 MonoTrampInfo
*tinfo
;
2277 gboolean is_in
= info
->subtype
== WRAPPER_SUBTYPE_GSHAREDVT_IN
;
2279 if (is_in
&& in_tinfo
)
2280 return in_tinfo
->code
;
2281 else if (!is_in
&& out_tinfo
)
2282 return out_tinfo
->code
;
2285 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2287 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2289 if (mono_ee_features
.use_aot_trampolines
)
2290 mono_aot_get_trampoline_full (is_in
? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo
);
2292 mono_arch_get_gsharedvt_trampoline (&tinfo
, FALSE
);
2293 jinfo
= create_jit_info_for_trampoline (method
, tinfo
);
2294 mono_jit_info_table_add (mono_get_root_domain (), jinfo
);
2307 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
, gboolean jit_only
, MonoError
*error
)
2309 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
2311 gpointer code
= NULL
, p
;
2313 MonoJitICallInfo
*callinfo
= NULL
;
2314 WrapperInfo
*winfo
= NULL
;
2315 gboolean use_interp
= FALSE
;
2319 if (mono_ee_features
.force_use_interpreter
&& !jit_only
)
2321 if (!use_interp
&& mono_interp_only_classes
) {
2322 for (GSList
*l
= mono_interp_only_classes
; l
; l
= l
->next
) {
2323 if (!strcmp (m_class_get_name (method
->klass
), (char*)l
->data
))
2328 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2334 /* Should be handled by the caller */
2335 g_assert (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
));
2338 * ICALL wrappers are handled specially, since there is only one copy of them
2339 * shared by all appdomains.
2341 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2342 winfo
= mono_marshal_get_wrapper_info (method
);
2343 if (winfo
&& winfo
->subtype
== WRAPPER_SUBTYPE_ICALL_WRAPPER
) {
2344 callinfo
= mono_find_jit_icall_by_addr (winfo
->d
.icall
.func
);
2345 g_assert (callinfo
);
2347 /* Must be domain neutral since there is only one copy */
2348 opt
|= MONO_OPT_SHARED
;
2350 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2351 opt
&= ~MONO_OPT_SHARED
;
2354 if (opt
& MONO_OPT_SHARED
)
2355 target_domain
= mono_get_root_domain ();
2357 target_domain
= domain
;
2359 if (method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2360 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2363 if (info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
2364 MonoGenericContext
*ctx
= NULL
;
2365 if (method
->is_inflated
)
2366 ctx
= mono_method_get_context (method
);
2367 method
= info
->d
.synchronized_inner
.method
;
2369 method
= mono_class_inflate_generic_method_checked (method
, ctx
, error
);
2370 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
2376 info
= lookup_method (target_domain
, method
);
2378 /* We can't use a domain specific method in another domain */
2379 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2382 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2383 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2387 if (!mono_runtime_class_init_full (vtable
, error
))
2389 return mono_create_ftnptr (target_domain
, info
->code_start
);
2393 #ifdef MONO_USE_AOT_COMPILER
2394 if (opt
& MONO_OPT_AOT
) {
2395 MonoDomain
*domain
= NULL
;
2397 if (mono_aot_mode
== MONO_AOT_MODE_INTERP
&& method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2398 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2400 if (info
->subtype
== WRAPPER_SUBTYPE_INTERP_IN
|| info
->subtype
== WRAPPER_SUBTYPE_INTERP_LMF
)
2401 /* AOT'd wrappers for interp must be owned by root domain */
2402 domain
= mono_get_root_domain ();
2406 domain
= mono_domain_get ();
2408 mono_class_init_internal (method
->klass
);
2410 code
= mono_aot_get_method (domain
, method
, error
);
2414 if (mono_gc_is_critical_method (method
)) {
2416 * The suspend code needs to be able to lookup these methods by ip in async context,
2417 * so preload their jit info.
2419 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, code
);
2424 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2425 * This is not a problem, since it will be initialized when the method is first
2426 * called by init_method ().
2428 if (!mono_llvm_only
&& !mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2429 vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2430 mono_error_assert_ok (error
);
2431 if (!mono_runtime_class_init_full (vtable
, error
))
2441 code
= compile_special (method
, target_domain
, error
);
2443 if (!mono_error_ok (error
))
2447 if (!jit_only
&& !code
&& mono_aot_only
&& mono_use_interpreter
&& method
->wrapper_type
!= MONO_WRAPPER_OTHER
) {
2448 if (mono_llvm_only
) {
2449 /* Signal to the caller that AOTed code is not found */
2452 code
= mini_get_interp_callbacks ()->create_method_pointer (method
, TRUE
, error
);
2454 if (!mono_error_ok (error
))
2459 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
2460 char *full_name
= mono_type_get_full_name (method
->klass
);
2461 mono_error_set_invalid_operation (error
, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name
);
2466 if (mono_aot_only
) {
2467 char *fullname
= mono_method_get_full_name (method
);
2468 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
);
2474 if (wait_or_register_method_to_compile (method
, target_domain
))
2476 code
= mono_jit_compile_method_inner (method
, target_domain
, opt
, error
);
2477 unregister_method_for_compile (method
, target_domain
);
2479 if (!mono_error_ok (error
))
2482 if (!code
&& mono_llvm_only
) {
2483 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method
, 1));
2484 g_assert_not_reached ();
2490 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2492 if ((method
->wrapper_type
== MONO_WRAPPER_WRITE_BARRIER
|| method
->wrapper_type
== MONO_WRAPPER_ALLOC
)) {
2496 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2498 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)code
, &d
);
2503 p
= mono_create_ftnptr (target_domain
, code
);
2506 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2507 mono_loader_lock ();
2509 if (!callinfo
->wrapper
) {
2510 callinfo
->wrapper
= p
;
2511 mono_register_jit_icall_wrapper (callinfo
, p
);
2514 mono_loader_unlock ();
2521 mono_jit_compile_method (MonoMethod
*method
, MonoError
*error
)
2525 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), FALSE
, error
);
2530 * mono_jit_compile_method_jit_only:
2532 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2535 mono_jit_compile_method_jit_only (MonoMethod
*method
, MonoError
*error
)
2539 code
= mono_jit_compile_method_with_opt (method
, mono_get_optimizations_for_method (method
, default_opt
), TRUE
, error
);
2543 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2545 invalidated_delegate_trampoline (char *desc
)
2547 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2548 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2554 * mono_jit_free_method:
2556 * Free all memory allocated by the JIT for METHOD.
2559 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
2561 MonoJitDynamicMethodInfo
*ji
;
2562 gboolean destroy
= TRUE
, removed
;
2563 GHashTableIter iter
;
2564 MonoJumpList
*jlist
;
2565 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2567 g_assert (method
->dynamic
);
2569 if (mono_use_interpreter
) {
2570 mono_domain_jit_code_hash_lock (domain
);
2571 /* InterpMethod is allocated in the domain mempool. We might haven't
2572 * allocated an InterpMethod for this instance yet */
2573 mono_internal_hash_table_remove (&info
->interp_code_hash
, method
);
2574 mono_domain_jit_code_hash_unlock (domain
);
2577 mono_domain_lock (domain
);
2578 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
2579 mono_domain_unlock (domain
);
2584 mono_debug_remove_method (method
, domain
);
2585 mono_lldb_remove_method (domain
, method
, ji
);
2587 mono_domain_lock (domain
);
2588 g_hash_table_remove (info
->dynamic_code_hash
, method
);
2589 mono_domain_jit_code_hash_lock (domain
);
2590 removed
= mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
2592 mono_domain_jit_code_hash_unlock (domain
);
2593 g_hash_table_remove (info
->jump_trampoline_hash
, method
);
2594 g_hash_table_remove (info
->seq_points
, method
);
2596 ji
->ji
->seq_points
= NULL
;
2598 /* requires the domain lock - took above */
2599 mono_conc_hashtable_remove (info
->runtime_invoke_hash
, method
);
2601 /* Remove jump targets in this method */
2602 g_hash_table_iter_init (&iter
, info
->jump_target_hash
);
2603 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&jlist
)) {
2604 GSList
*tmp
, *remove
;
2607 for (tmp
= jlist
->list
; tmp
; tmp
= tmp
->next
) {
2608 guint8
*ip
= (guint8
*)tmp
->data
;
2610 if (ip
>= (guint8
*)ji
->ji
->code_start
&& ip
< (guint8
*)ji
->ji
->code_start
+ ji
->ji
->code_size
)
2611 remove
= g_slist_prepend (remove
, tmp
);
2613 for (tmp
= remove
; tmp
; tmp
= tmp
->next
) {
2614 jlist
->list
= g_slist_delete_link ((GSList
*)jlist
->list
, (GSList
*)tmp
->data
);
2616 g_slist_free (remove
);
2618 mono_domain_unlock (domain
);
2620 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2621 if (mini_debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2623 * Instead of freeing the code, change it to call an error routine
2624 * so people can fix their code.
2626 char *type
= mono_type_full_name (m_class_get_byval_arg (method
->klass
));
2627 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
2630 mono_arch_invalidate_method (ji
->ji
, (gpointer
)invalidated_delegate_trampoline
, (gpointer
)type_and_method
);
2636 * This needs to be done before freeing code_mp, since the code address is the
2637 * key in the table, so if we free the code_mp first, another thread can grab the
2638 * same code address and replace our entry in the table.
2640 mono_jit_info_table_remove (domain
, ji
->ji
);
2643 mono_code_manager_destroy (ji
->code_mp
);
2648 mono_jit_search_all_backends_for_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**out_ji
)
2653 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
2655 ERROR_DECL (oerror
);
2657 /* Might be AOTed code */
2658 mono_class_init_internal (method
->klass
);
2659 code
= mono_aot_get_method (domain
, method
, oerror
);
2661 mono_error_assert_ok (oerror
);
2662 ji
= mono_jit_info_table_find (domain
, code
);
2664 if (!is_ok (oerror
))
2665 mono_error_cleanup (oerror
);
2667 /* Might be interpreted */
2668 ji
= mini_get_interp_callbacks ()->find_jit_info (domain
, method
);
2678 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
2680 MonoDomain
*target_domain
;
2683 if (default_opt
& MONO_OPT_SHARED
)
2684 target_domain
= mono_get_root_domain ();
2686 target_domain
= domain
;
2688 info
= lookup_method (target_domain
, method
);
2690 /* We can't use a domain specific method in another domain */
2691 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
2692 mono_atomic_inc_i32 (&mono_jit_stats
.methods_lookups
);
2695 return info
->code_start
;
2704 static guint32 bisect_opt
= 0;
2705 static GHashTable
*bisect_methods_hash
= NULL
;
2708 mono_set_bisect_methods (guint32 opt
, const char *method_list_filename
)
2711 char method_name
[2048];
2714 bisect_methods_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
2715 g_assert (bisect_methods_hash
);
2717 file
= fopen (method_list_filename
, "r");
2720 while (fgets (method_name
, sizeof (method_name
), file
)) {
2721 size_t len
= strlen (method_name
);
2723 g_assert (method_name
[len
- 1] == '\n');
2724 method_name
[len
- 1] = 0;
2725 g_hash_table_insert (bisect_methods_hash
, g_strdup (method_name
), GINT_TO_POINTER (1));
2727 g_assert (feof (file
));
2730 gboolean mono_do_single_method_regression
= FALSE
;
2731 guint32 mono_single_method_regression_opt
= 0;
2732 MonoMethod
*mono_current_single_method
;
2733 GSList
*mono_single_method_list
;
2734 GHashTable
*mono_single_method_hash
;
2737 mono_get_optimizations_for_method (MonoMethod
*method
, guint32 opt
)
2741 if (bisect_methods_hash
) {
2742 char *name
= mono_method_full_name (method
, TRUE
);
2743 void *res
= g_hash_table_lookup (bisect_methods_hash
, name
);
2746 return opt
| bisect_opt
;
2748 if (!mono_do_single_method_regression
)
2750 if (!mono_current_single_method
) {
2751 if (!mono_single_method_hash
)
2752 mono_single_method_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2753 if (!g_hash_table_lookup (mono_single_method_hash
, method
)) {
2754 g_hash_table_insert (mono_single_method_hash
, method
, method
);
2755 mono_single_method_list
= g_slist_prepend (mono_single_method_list
, method
);
2759 if (method
== mono_current_single_method
)
2760 return mono_single_method_regression_opt
;
2765 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
2767 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
2772 gpointer compiled_method
;
2773 gpointer runtime_invoke
;
2775 MonoDynCallInfo
*dyn_call_info
;
2776 MonoClass
*ret_box_class
;
2777 MonoMethodSignature
*sig
;
2778 gboolean gsharedvt_invoke
;
2779 gboolean use_interp
;
2780 gpointer
*wrapper_arg
;
2781 } RuntimeInvokeInfo
;
2783 static RuntimeInvokeInfo
*
2784 create_runtime_invoke_info (MonoDomain
*domain
, MonoMethod
*method
, gpointer compiled_method
, gboolean callee_gsharedvt
, gboolean use_interp
, MonoError
*error
)
2787 RuntimeInvokeInfo
*info
;
2789 info
= g_new0 (RuntimeInvokeInfo
, 1);
2790 info
->compiled_method
= compiled_method
;
2791 info
->use_interp
= use_interp
;
2792 if (mono_llvm_only
&& method
->string_ctor
)
2793 info
->sig
= mono_marshal_get_string_ctor_signature (method
);
2795 info
->sig
= mono_method_signature_internal (method
);
2797 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
2798 info
->vtable
= mono_class_vtable_checked (domain
, method
->klass
, error
);
2799 if (!mono_error_ok (error
))
2801 g_assert (info
->vtable
);
2803 MonoMethodSignature
*sig
= info
->sig
;
2807 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2808 * in full-aot mode, so we use a slower, but more generic wrapper if
2809 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2811 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2812 if (!mono_llvm_only
&& (mono_aot_only
|| mini_debug_options
.dyn_runtime_invoke
)) {
2813 gboolean supported
= TRUE
;
2816 if (method
->string_ctor
)
2817 sig
= mono_marshal_get_string_ctor_signature (method
);
2819 for (i
= 0; i
< sig
->param_count
; ++i
) {
2820 MonoType
*t
= sig
->params
[i
];
2822 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2826 if (mono_class_is_contextbound (method
->klass
) || !info
->compiled_method
)
2830 info
->dyn_call_info
= mono_arch_dyn_call_prepare (sig
);
2831 if (mini_debug_options
.dyn_runtime_invoke
)
2832 g_assert (info
->dyn_call_info
);
2837 ret_type
= sig
->ret
;
2838 switch (ret_type
->type
) {
2839 case MONO_TYPE_VOID
:
2851 case MONO_TYPE_BOOLEAN
:
2852 case MONO_TYPE_CHAR
:
2855 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2858 info
->ret_box_class
= mono_defaults
.int_class
;
2860 case MONO_TYPE_STRING
:
2861 case MONO_TYPE_CLASS
:
2862 case MONO_TYPE_ARRAY
:
2863 case MONO_TYPE_SZARRAY
:
2864 case MONO_TYPE_OBJECT
:
2866 case MONO_TYPE_GENERICINST
:
2867 if (!MONO_TYPE_IS_REFERENCE (ret_type
))
2868 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2870 case MONO_TYPE_VALUETYPE
:
2871 info
->ret_box_class
= mono_class_from_mono_type_internal (ret_type
);
2874 g_assert_not_reached ();
2878 if (info
->use_interp
)
2881 if (!info
->dyn_call_info
) {
2882 if (mono_llvm_only
) {
2883 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2884 g_assert_not_reached ();
2886 info
->gsharedvt_invoke
= TRUE
;
2887 if (!callee_gsharedvt
) {
2888 /* Invoke a gsharedvt out wrapper instead */
2889 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2890 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2892 info
->wrapper_arg
= g_malloc0 (2 * sizeof (gpointer
));
2893 info
->wrapper_arg
[0] = mini_llvmonly_add_method_wrappers (method
, info
->compiled_method
, FALSE
, FALSE
, &(info
->wrapper_arg
[1]));
2895 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2896 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2897 g_free (wrapper_sig
);
2899 info
->compiled_method
= mono_jit_compile_method (wrapper
, error
);
2900 if (!mono_error_ok (error
)) {
2905 /* Gsharedvt methods can be invoked the same way */
2906 /* The out wrapper has the same signature as the compiled gsharedvt method */
2907 MonoMethodSignature
*wrapper_sig
= mini_get_gsharedvt_out_sig_wrapper_signature (sig
->hasthis
, sig
->ret
->type
!= MONO_TYPE_VOID
, sig
->param_count
);
2909 info
->wrapper_arg
= (gpointer
*)(mono_method_needs_static_rgctx_invoke (method
, TRUE
) ? mini_method_get_rgctx (method
) : NULL
);
2911 invoke
= mono_marshal_get_runtime_invoke_for_sig (wrapper_sig
);
2912 g_free (wrapper_sig
);
2915 info
->runtime_invoke
= mono_jit_compile_method (invoke
, error
);
2916 if (!mono_error_ok (error
)) {
2926 mono_llvmonly_runtime_invoke (MonoMethod
*method
, RuntimeInvokeInfo
*info
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2928 MonoMethodSignature
*sig
= info
->sig
;
2929 MonoDomain
*domain
= mono_domain_get ();
2930 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
2932 gpointer retval_ptr
;
2933 guint8 retval
[256];
2934 gpointer
*param_refs
;
2939 g_assert (info
->gsharedvt_invoke
);
2942 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2943 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2944 * signatures, so we only have to generate runtime invoke wrappers for these
2946 * This code also handles invocation of gsharedvt methods directly, no
2947 * out wrappers are used in that case.
2949 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2950 param_refs
= (gpointer
*)g_alloca ((sig
->param_count
+ sig
->hasthis
+ 2) * sizeof (gpointer
));
2953 * The runtime invoke wrappers expects pointers to primitive types, so have to
2957 args
[pindex
++] = &obj
;
2958 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
2959 retval_ptr
= (gpointer
)&retval
;
2960 args
[pindex
++] = &retval_ptr
;
2962 for (i
= 0; i
< sig
->param_count
; ++i
) {
2963 MonoType
*t
= sig
->params
[i
];
2965 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
2966 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
2967 guint8
*nullable_buf
;
2970 size
= mono_class_value_size (klass
, NULL
);
2971 nullable_buf
= g_alloca (size
);
2972 g_assert (nullable_buf
);
2974 /* The argument pointed to by params [i] is either a boxed vtype or null */
2975 mono_nullable_init (nullable_buf
, (MonoObject
*)params
[i
], klass
);
2976 params
[i
] = nullable_buf
;
2979 if (!t
->byref
&& (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
)) {
2980 param_refs
[i
] = params
[i
];
2981 params
[i
] = &(param_refs
[i
]);
2983 args
[pindex
++] = ¶ms
[i
];
2985 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2986 args
[pindex
++] = &info
->wrapper_arg
;
2988 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
2990 runtime_invoke (NULL
, args
, exc
, info
->compiled_method
);
2994 if (sig
->ret
->type
!= MONO_TYPE_VOID
&& info
->ret_box_class
)
2995 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
2997 return *(MonoObject
**)retval
;
3001 * mono_jit_runtime_invoke:
3002 * \param method: the method to invoke
3003 * \param obj: this pointer
3004 * \param params: array of parameter values.
3005 * \param exc: Set to the exception raised in the managed method.
3006 * \param error: error or caught exception object
3007 * If \p exc is NULL, \p error is thrown instead.
3008 * If coop is enabled, \p exc argument is ignored -
3009 * all exceptions are caught and propagated through \p error
3012 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
3014 MonoMethod
*invoke
, *callee
;
3015 MonoObject
*(*runtime_invoke
) (MonoObject
*this_obj
, void **params
, MonoObject
**exc
, void* compiled_method
);
3016 MonoDomain
*domain
= mono_domain_get ();
3017 MonoJitDomainInfo
*domain_info
;
3018 RuntimeInvokeInfo
*info
, *info2
;
3019 MonoJitInfo
*ji
= NULL
;
3020 gboolean callee_gsharedvt
= FALSE
;
3022 if (mono_ee_features
.force_use_interpreter
)
3023 return mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3029 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
3030 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3034 domain_info
= domain_jit_info (domain
);
3036 info
= (RuntimeInvokeInfo
*)mono_conc_hashtable_lookup (domain_info
->runtime_invoke_hash
, method
);
3039 if (mono_security_core_clr_enabled ()) {
3041 * This might be redundant since mono_class_vtable () already does this,
3042 * but keep it just in case for moonlight.
3044 mono_class_setup_vtable (method
->klass
);
3045 if (mono_class_has_failure (method
->klass
)) {
3046 mono_error_set_for_class_failure (error
, method
->klass
);
3048 *exc
= (MonoObject
*)mono_class_get_exception_for_failure (method
->klass
);
3053 gpointer compiled_method
;
3056 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3057 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3059 * Array Get/Set/Address methods. The JIT implements them using inline code
3060 * inside the runtime invoke wrappers, so no need to compile them.
3062 if (mono_aot_only
) {
3064 * Call a wrapper, since the runtime invoke wrapper was not generated.
3066 MonoMethod
*wrapper
;
3068 wrapper
= mono_marshal_get_array_accessor_wrapper (method
);
3069 invoke
= mono_marshal_get_runtime_invoke (wrapper
, FALSE
);
3076 gboolean use_interp
= FALSE
;
3079 compiled_method
= mono_jit_compile_method_jit_only (callee
, error
);
3080 if (!compiled_method
) {
3081 g_assert (!mono_error_ok (error
));
3083 if (mono_use_interpreter
)
3088 if (mono_llvm_only
) {
3089 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
3090 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
3091 if (callee_gsharedvt
)
3092 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
3095 if (!callee_gsharedvt
)
3096 compiled_method
= mini_add_method_trampoline (callee
, compiled_method
, mono_method_needs_static_rgctx_invoke (callee
, TRUE
), FALSE
);
3099 compiled_method
= NULL
;
3102 info
= create_runtime_invoke_info (domain
, method
, compiled_method
, callee_gsharedvt
, use_interp
, error
);
3103 if (!mono_error_ok (error
))
3106 mono_domain_lock (domain
);
3107 info2
= (RuntimeInvokeInfo
*)mono_conc_hashtable_insert (domain_info
->runtime_invoke_hash
, method
, info
);
3108 mono_domain_unlock (domain
);
3116 * We need this here because mono_marshal_get_runtime_invoke can place
3117 * the helper method in System.Object and not the target class.
3119 if (!mono_runtime_class_init_full (info
->vtable
, error
)) {
3121 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3125 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3126 we always catch the exception and propagate it through the MonoError */
3127 gboolean catchExcInMonoError
=
3128 (exc
== NULL
) && mono_threads_are_safepoints_enabled ();
3129 MonoObject
*invoke_exc
= NULL
;
3130 if (catchExcInMonoError
)
3133 /* The wrappers expect this to be initialized to NULL */
3137 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3138 static RuntimeInvokeDynamicFunction dyn_runtime_invoke
= NULL
;
3139 if (info
->dyn_call_info
) {
3140 if (!dyn_runtime_invoke
) {
3141 mono_domain_lock (domain
);
3143 invoke
= mono_marshal_get_runtime_invoke_dynamic ();
3144 dyn_runtime_invoke
= (RuntimeInvokeDynamicFunction
)mono_jit_compile_method_jit_only (invoke
, error
);
3145 if (!dyn_runtime_invoke
&& mono_use_interpreter
) {
3146 info
->use_interp
= TRUE
;
3147 info
->dyn_call_info
= NULL
;
3148 } else if (!mono_error_ok (error
)) {
3149 mono_domain_unlock (domain
);
3152 mono_domain_unlock (domain
);
3155 if (info
->dyn_call_info
) {
3156 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
3158 int i
, pindex
, buf_size
;
3160 guint8 retval
[256];
3162 /* Convert the arguments to the format expected by start_dyn_call () */
3163 args
= (void **)g_alloca ((sig
->param_count
+ sig
->hasthis
) * sizeof (gpointer
));
3166 args
[pindex
++] = &obj
;
3167 for (i
= 0; i
< sig
->param_count
; ++i
) {
3168 MonoType
*t
= sig
->params
[i
];
3171 args
[pindex
++] = ¶ms
[i
];
3172 } else if (MONO_TYPE_IS_REFERENCE (t
) || t
->type
== MONO_TYPE_PTR
) {
3173 args
[pindex
++] = ¶ms
[i
];
3175 args
[pindex
++] = params
[i
];
3179 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3181 buf_size
= mono_arch_dyn_call_get_buf_size (info
->dyn_call_info
);
3182 buf
= g_alloca (buf_size
);
3183 memset (buf
, 0, buf_size
);
3186 mono_arch_start_dyn_call (info
->dyn_call_info
, (gpointer
**)args
, retval
, buf
);
3188 dyn_runtime_invoke (buf
, exc
, info
->compiled_method
);
3189 mono_arch_finish_dyn_call (info
->dyn_call_info
, buf
);
3191 if (catchExcInMonoError
&& *exc
!= NULL
) {
3192 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3196 if (info
->ret_box_class
)
3197 return mono_value_box_checked (domain
, info
->ret_box_class
, retval
, error
);
3199 return *(MonoObject
**)retval
;
3205 if (info
->use_interp
) {
3206 result
= mini_get_interp_callbacks ()->runtime_invoke (method
, obj
, params
, exc
, error
);
3207 return_val_if_nok (error
, NULL
);
3208 } else if (mono_llvm_only
) {
3209 result
= mono_llvmonly_runtime_invoke (method
, info
, obj
, params
, exc
, error
);
3213 runtime_invoke
= (MonoObject
*(*)(MonoObject
*, void **, MonoObject
**, void *))info
->runtime_invoke
;
3215 result
= runtime_invoke ((MonoObject
*)obj
, params
, exc
, info
->compiled_method
);
3217 if (catchExcInMonoError
&& *exc
!= NULL
) {
3218 ((MonoException
*)(*exc
))->caught_in_unmanaged
= TRUE
;
3219 mono_error_set_exception_instance (error
, (MonoException
*) *exc
);
3224 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler
)
3226 MonoException
*exc
= NULL
;
3228 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3229 MONO_SIG_HANDLER_GET_CONTEXT
;
3231 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3233 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3235 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3236 if (mono_arch_is_int_overflow (ctx
, info
))
3238 * The spec says this throws ArithmeticException, but MS throws the derived
3239 * OverflowException.
3241 exc
= mono_get_exception_overflow ();
3243 exc
= mono_get_exception_divide_by_zero ();
3245 exc
= mono_get_exception_divide_by_zero ();
3249 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3252 mono_handle_native_crash ("SIGFPE", ctx
, info
);
3253 if (mono_do_crash_chaining
) {
3254 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3259 mono_arch_handle_exception (ctx
, exc
);
3262 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3265 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler
)
3267 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3268 MONO_SIG_HANDLER_GET_CONTEXT
;
3270 if (mono_runtime_get_no_exec ())
3274 mono_handle_native_crash ("SIGILL", ctx
, info
);
3275 if (mono_do_crash_chaining
) {
3276 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3280 g_assert_not_reached ();
3283 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3285 #define HAVE_SIG_INFO
3286 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3288 #ifdef MONO_SIG_HANDLER_DEBUG
3289 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3290 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3291 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3292 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3293 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3294 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3300 is_addr_implicit_null_check (void *addr
)
3302 /* implicit null checks are only expected to work on the first page. larger
3303 * offsets are expected to have an explicit null check */
3304 return addr
<= GUINT_TO_POINTER (mono_target_pagesize ());
3307 // This function is separate from mono_sigsegv_signal_handler
3308 // so debug_fault_addr can be seen in debugger stacks.
3309 #ifdef MONO_SIG_HANDLER_DEBUG
3311 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug
)
3313 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3317 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3318 gpointer fault_addr
= NULL
;
3319 #ifdef HAVE_SIG_INFO
3320 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
3324 MONO_SIG_HANDLER_GET_CONTEXT
;
3326 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3327 if (mono_arch_is_single_step_event (info
, ctx
)) {
3328 mini_get_dbg_callbacks ()->single_step_event (ctx
);
3330 } else if (mono_arch_is_breakpoint_event (info
, ctx
)) {
3331 mini_get_dbg_callbacks ()->breakpoint_hit (ctx
);
3336 #if defined(HAVE_SIG_INFO)
3337 #if !defined(HOST_WIN32)
3338 fault_addr
= info
->si_addr
;
3339 if (mono_aot_is_pagefault (info
->si_addr
)) {
3340 mono_aot_handle_pagefault (info
->si_addr
);
3345 /* The thread might no be registered with the runtime */
3346 if (!mono_domain_get () || !jit_tls
) {
3347 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3349 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3350 if (mono_do_crash_chaining
) {
3351 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3357 ji
= mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
3359 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3360 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, info
, (guint8
*)info
->si_addr
))
3363 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3364 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3365 fault_addr
= info
->si_addr
;
3366 if (fault_addr
== NULL
) {
3369 mono_sigctx_to_monoctx (ctx
, &mctx
);
3371 fault_addr
= MONO_CONTEXT_GET_SP (&mctx
);
3375 if (jit_tls
->stack_size
&&
3376 ABS ((guint8
*)fault_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 8192 * sizeof (gpointer
)) {
3378 * The hard-guard page has been hit: there is not much we can do anymore
3379 * Print a hopefully clear message and abort.
3381 mono_handle_hard_stack_ovf (jit_tls
, ji
, ctx
, (guint8
*)info
->si_addr
);
3382 g_assert_not_reached ();
3384 /* The original handler might not like that it is executed on an altstack... */
3385 if (!ji
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3388 if (is_addr_implicit_null_check (info
->si_addr
)) {
3389 mono_arch_handle_altstack_exception (ctx
, info
, info
->si_addr
, FALSE
);
3391 mono_handle_native_crash ("SIGSEGV", ctx
, info
);
3397 if (!mono_do_crash_chaining
&& mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
3400 mono_handle_native_crash ("SIGSEGV", ctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3402 if (mono_do_crash_chaining
) {
3403 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
3408 if (is_addr_implicit_null_check (fault_addr
)) {
3409 mono_arch_handle_exception (ctx
, NULL
);
3411 mono_handle_native_crash ("SIGSEGV", ctx
, (MONO_SIG_HANDLER_INFO_TYPE
*)info
);
3416 #ifdef MONO_SIG_HANDLER_DEBUG
3418 // This function is separate from mono_sigsegv_signal_handler_debug
3419 // so debug_fault_addr can be seen in debugger stacks.
3420 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler
)
3423 gpointer
const debug_fault_addr
= (gpointer
)MONO_SIG_HANDLER_GET_INFO () ->ep
->ExceptionRecord
->ExceptionInformation
[1];
3424 #elif defined (HAVE_SIG_INFO)
3425 gpointer
const debug_fault_addr
= MONO_SIG_HANDLER_GET_INFO ()->si_addr
;
3427 #error No extra parameter is passed, not even 0, to avoid any confusion.
3429 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG
);
3432 #endif // MONO_SIG_HANDLER_DEBUG
3434 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler
)
3437 MONO_SIG_HANDLER_GET_CONTEXT
;
3439 MONO_ENTER_GC_UNSAFE_UNBALANCED
;
3441 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3443 mono_arch_handle_exception (ctx
, exc
);
3445 MONO_EXIT_GC_UNSAFE_UNBALANCED
;
3448 #ifndef DISABLE_REMOTING
3449 /* mono_jit_create_remoting_trampoline:
3450 * @method: pointer to the method info
3452 * Creates a trampoline which calls the remoting functions. This
3453 * is used in the vtable of transparent proxies.
3455 * Returns: a pointer to the newly created code
3458 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
3461 guint8
*addr
= NULL
;
3465 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature_internal (method
)->generic_param_count
) {
3466 return mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
3470 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
3471 (mono_method_signature_internal (method
)->hasthis
&& (mono_class_is_marshalbyref (method
->klass
) || method
->klass
== mono_defaults
.object_class
)))
3472 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
, error
);
3475 return_val_if_nok (error
, NULL
);
3476 addr
= (guint8
*)mono_compile_method_checked (nm
, error
);
3477 return_val_if_nok (error
, NULL
);
3478 return mono_get_addr_from_ftnptr (addr
);
3482 static G_GNUC_UNUSED
void
3483 no_imt_trampoline (void)
3485 g_assert_not_reached ();
3488 static G_GNUC_UNUSED
void
3489 no_vcall_trampoline (void)
3491 g_assert_not_reached ();
3494 static gpointer
*vtable_trampolines
;
3495 static int vtable_trampolines_size
;
3498 mini_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
)
3500 int index
= slot_index
+ MONO_IMT_SIZE
;
3503 return mini_llvmonly_get_vtable_trampoline (vt
, slot_index
, index
);
3505 g_assert (slot_index
>= - MONO_IMT_SIZE
);
3506 if (!vtable_trampolines
|| slot_index
+ MONO_IMT_SIZE
>= vtable_trampolines_size
) {
3508 if (!vtable_trampolines
|| index
>= vtable_trampolines_size
) {
3512 new_size
= vtable_trampolines_size
? vtable_trampolines_size
* 2 : 128;
3513 while (new_size
<= index
)
3515 new_table
= g_new0 (gpointer
, new_size
);
3517 if (vtable_trampolines
)
3518 memcpy (new_table
, vtable_trampolines
, vtable_trampolines_size
* sizeof (gpointer
));
3519 g_free (vtable_trampolines
);
3520 mono_memory_barrier ();
3521 vtable_trampolines
= (void **)new_table
;
3522 vtable_trampolines_size
= new_size
;
3527 if (!vtable_trampolines
[index
])
3528 vtable_trampolines
[index
] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index
), MONO_TRAMPOLINE_VCALL
, mono_get_root_domain (), NULL
);
3529 return vtable_trampolines
[index
];
3533 mini_get_imt_trampoline (MonoVTable
*vt
, int slot_index
)
3535 return mini_get_vtable_trampoline (vt
, slot_index
- MONO_IMT_SIZE
);
3539 mini_imt_entry_inited (MonoVTable
*vt
, int imt_slot_index
)
3544 gpointer
*imt
= (gpointer
*)vt
;
3545 imt
-= MONO_IMT_SIZE
;
3547 return (imt
[imt_slot_index
] != mini_get_imt_trampoline (vt
, imt_slot_index
));
3551 create_delegate_method_ptr (MonoMethod
*method
, MonoError
*error
)
3555 if (method_is_dynamic (method
)) {
3556 /* Creating a trampoline would leak memory */
3557 func
= mono_compile_method_checked (method
, error
);
3558 return_val_if_nok (error
, NULL
);
3560 gpointer trampoline
= mono_runtime_create_jump_trampoline (mono_domain_get (), method
, TRUE
, error
);
3561 return_val_if_nok (error
, NULL
);
3562 func
= mono_create_ftnptr (mono_domain_get (), trampoline
);
3568 mini_init_delegate (MonoDelegateHandle delegate
, MonoError
*error
)
3570 MonoDelegate
*del
= MONO_HANDLE_RAW (delegate
);
3572 if (!del
->method_ptr
) {
3573 g_assert (del
->method
);
3574 del
->method_ptr
= create_delegate_method_ptr (del
->method
, error
);
3575 return_if_nok (error
);
3578 if (mono_use_interpreter
)
3579 mini_get_interp_callbacks ()->init_delegate (del
);
3581 del
->extra_arg
= mini_llvmonly_get_delegate_arg (del
->method
, del
->method_ptr
);
3585 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg
, int offset
)
3589 abs_offset
= offset
;
3591 abs_offset
= - abs_offset
;
3592 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg
? "_imt" : "", offset
< 0 ? "m_" : "", abs_offset
/ TARGET_SIZEOF_VOID_P
);
3596 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
)
3598 gboolean is_virtual_generic
, is_interface
, load_imt_reg
;
3601 static guint8
**cache
= NULL
;
3602 static int cache_size
= 0;
3607 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
3610 is_virtual_generic
= method
->is_inflated
&& mono_method_get_declaring_generic_method (method
)->is_generic
;
3611 is_interface
= mono_class_is_interface (method
->klass
);
3612 load_imt_reg
= is_virtual_generic
|| is_interface
;
3615 offset
= ((gint32
)mono_method_get_imt_slot (method
) - MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
3617 offset
= MONO_STRUCT_OFFSET (MonoVTable
, vtable
) + ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
3619 idx
= (offset
/ TARGET_SIZEOF_VOID_P
+ MONO_IMT_SIZE
) * 2 + (load_imt_reg
? 1 : 0);
3620 g_assert (idx
>= 0);
3622 /* Resize the cache to idx + 1 */
3623 if (cache_size
< idx
+ 1) {
3625 if (cache_size
< idx
+ 1) {
3627 int new_cache_size
= idx
+ 1;
3629 new_cache
= g_new0 (guint8
*, new_cache_size
);
3631 memcpy (new_cache
, cache
, cache_size
* sizeof (guint8
*));
3634 mono_memory_barrier ();
3636 cache_size
= new_cache_size
;
3644 /* FIXME Support more cases */
3645 if (mono_ee_features
.use_aot_trampolines
) {
3646 cache
[idx
] = (guint8
*)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg
, offset
));
3647 g_assert (cache
[idx
]);
3649 cache
[idx
] = (guint8
*)mono_arch_get_delegate_virtual_invoke_impl (sig
, method
, offset
, load_imt_reg
);
3655 * mini_parse_debug_option:
3656 * @option: The option to parse.
3658 * Parses debug options for the mono runtime. The options are the same as for
3659 * the MONO_DEBUG environment variable.
3663 mini_parse_debug_option (const char *option
)
3665 // Empty string is ok as consequence of appending ",foo"
3666 // without first checking for empty.
3670 if (!strcmp (option
, "handle-sigint"))
3671 mini_debug_options
.handle_sigint
= TRUE
;
3672 else if (!strcmp (option
, "keep-delegates"))
3673 mini_debug_options
.keep_delegates
= TRUE
;
3674 else if (!strcmp (option
, "reverse-pinvoke-exceptions"))
3675 mini_debug_options
.reverse_pinvoke_exceptions
= TRUE
;
3676 else if (!strcmp (option
, "collect-pagefault-stats"))
3677 mini_debug_options
.collect_pagefault_stats
= TRUE
;
3678 else if (!strcmp (option
, "break-on-unverified"))
3679 mini_debug_options
.break_on_unverified
= TRUE
;
3680 else if (!strcmp (option
, "no-gdb-backtrace"))
3681 mini_debug_options
.no_gdb_backtrace
= TRUE
;
3682 else if (!strcmp (option
, "suspend-on-native-crash") || !strcmp (option
, "suspend-on-sigsegv"))
3683 mini_debug_options
.suspend_on_native_crash
= TRUE
;
3684 else if (!strcmp (option
, "suspend-on-exception"))
3685 mini_debug_options
.suspend_on_exception
= TRUE
;
3686 else if (!strcmp (option
, "suspend-on-unhandled"))
3687 mini_debug_options
.suspend_on_unhandled
= TRUE
;
3688 else if (!strcmp (option
, "dont-free-domains"))
3689 mono_dont_free_domains
= TRUE
;
3690 else if (!strcmp (option
, "dyn-runtime-invoke"))
3691 mini_debug_options
.dyn_runtime_invoke
= TRUE
;
3692 else if (!strcmp (option
, "gdb"))
3693 mini_debug_options
.gdb
= TRUE
;
3694 else if (!strcmp (option
, "lldb"))
3695 mini_debug_options
.lldb
= TRUE
;
3696 else if (!strcmp (option
, "explicit-null-checks"))
3697 mini_debug_options
.explicit_null_checks
= TRUE
;
3698 else if (!strcmp (option
, "gen-seq-points"))
3699 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
3700 else if (!strcmp (option
, "gen-compact-seq-points"))
3701 fprintf (stderr
, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3702 else if (!strcmp (option
, "no-compact-seq-points"))
3703 mini_debug_options
.no_seq_points_compact_data
= TRUE
;
3704 else if (!strcmp (option
, "single-imm-size"))
3705 mini_debug_options
.single_imm_size
= TRUE
;
3706 else if (!strcmp (option
, "init-stacks"))
3707 mini_debug_options
.init_stacks
= TRUE
;
3708 else if (!strcmp (option
, "casts"))
3709 mini_debug_options
.better_cast_details
= TRUE
;
3710 else if (!strcmp (option
, "soft-breakpoints"))
3711 mini_debug_options
.soft_breakpoints
= TRUE
;
3712 else if (!strcmp (option
, "check-pinvoke-callconv"))
3713 mini_debug_options
.check_pinvoke_callconv
= TRUE
;
3714 else if (!strcmp (option
, "use-fallback-tls"))
3715 mini_debug_options
.use_fallback_tls
= TRUE
;
3716 else if (!strcmp (option
, "debug-domain-unload"))
3717 mono_enable_debug_domain_unload (TRUE
);
3718 else if (!strcmp (option
, "partial-sharing"))
3719 mono_set_partial_sharing_supported (TRUE
);
3720 else if (!strcmp (option
, "align-small-structs"))
3721 mono_align_small_structs
= TRUE
;
3722 else if (!strcmp (option
, "native-debugger-break"))
3723 mini_debug_options
.native_debugger_break
= TRUE
;
3724 else if (!strcmp (option
, "disable_omit_fp"))
3725 mini_debug_options
.disable_omit_fp
= TRUE
;
3726 // This is an internal testing feature.
3727 // Every tail. encountered is required to be optimized.
3729 else if (!strcmp (option
, "test-tailcall-require"))
3730 mini_debug_options
.test_tailcall_require
= TRUE
;
3731 else if (!strcmp (option
, "verbose-gdb"))
3732 mini_debug_options
.verbose_gdb
= TRUE
;
3733 else if (!strncmp (option
, "thread-dump-dir=", 16))
3734 mono_set_thread_dump_dir(g_strdup(option
+ 16));
3735 else if (!strncmp (option
, "aot-skip=", 9)) {
3736 mini_debug_options
.aot_skip_set
= TRUE
;
3737 mini_debug_options
.aot_skip
= atoi (option
+ 9);
3745 mini_parse_debug_options (void)
3747 char *options
= g_getenv ("MONO_DEBUG");
3748 gchar
**args
, **ptr
;
3753 args
= g_strsplit (options
, ",", -1);
3756 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
3757 const char *arg
= *ptr
;
3759 if (!mini_parse_debug_option (arg
)) {
3760 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
3761 // test-tailcall-require is also accepted but not documented.
3762 // empty string is also accepted and ignored as a consequence
3763 // of appending ",foo" without checking for empty.
3764 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");
3773 mini_get_debug_options (void)
3775 return &mini_debug_options
;
3779 mini_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
3781 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3782 gpointer
* desc
= NULL
;
3784 if ((desc
= g_hash_table_lookup (domain
->ftnptrs_hash
, addr
)))
3786 #if defined(__mono_ppc64__)
3787 desc
= mono_domain_alloc0 (domain
, 3 * sizeof (gpointer
));
3793 g_hash_table_insert (domain
->ftnptrs_hash
, addr
, desc
);
3801 mini_get_addr_from_ftnptr (gpointer descr
)
3803 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3804 return *(gpointer
*)descr
;
3811 register_jit_stats (void)
3813 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_compiled
);
3814 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_aot
);
3815 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_without_llvm
);
3816 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_llvm
);
3817 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_with_interp
);
3818 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_method_to_ir
);
3819 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses
);
3820 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
);
3821 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_long_opts
);
3822 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_typechecks
);
3823 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop
);
3824 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_emulate_ops
);
3825 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches
);
3826 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs
);
3827 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce
);
3828 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_alias_analysis
);
3829 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_if_conversion
);
3830 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_bb_ordering
);
3831 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compile_dominator_info
);
3832 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_compute_natural_loops
);
3833 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_insert_safepoints
);
3834 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_compute
);
3835 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_cprop
);
3836 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_deadce
);
3837 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_perform_abc_removal
);
3838 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_ssa_remove
);
3839 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop2
);
3840 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_handle_global_vregs2
);
3841 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce2
);
3842 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_optimize_branches2
);
3843 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_vtype_opts
);
3844 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_decompose_array_access_opts
);
3845 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_liveness_handle_exception_clauses2
);
3846 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_analyze_liveness
);
3847 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_linear_scan
);
3848 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_arch_allocate_vars
);
3849 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_spill_global_vars
);
3850 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_cprop3
);
3851 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_local_deadce3
);
3852 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_codegen
);
3853 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_create_jit_info
);
3854 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_gc_create_gc_map
);
3855 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_save_seq_point_info
);
3856 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT
| MONO_COUNTER_DOUBLE
, &mono_jit_stats
.jit_time
);
3857 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.basic_blocks
);
3858 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.max_basic_blocks
);
3859 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocate_var
);
3860 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.code_reallocs
);
3861 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_code_size
);
3862 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.allocated_seq_points_size
);
3863 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlineable_methods
);
3864 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.inlined_methods
);
3865 mono_counters_register ("Regvars", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.regvars
);
3866 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.locals_stack_size
);
3867 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.methods_lookups
);
3868 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.cil_code_size
);
3869 mono_counters_register ("Native code size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.native_code_size
);
3870 mono_counters_register ("Aliases found", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_found
);
3871 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.alias_removed
);
3872 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.loads_eliminated
);
3873 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.stores_eliminated
);
3874 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &mono_jit_stats
.optimized_divisions
);
3877 static void runtime_invoke_info_free (gpointer value
);
3880 class_method_pair_equal (gconstpointer ka
, gconstpointer kb
)
3882 const MonoClassMethodPair
*apair
= (const MonoClassMethodPair
*)ka
;
3883 const MonoClassMethodPair
*bpair
= (const MonoClassMethodPair
*)kb
;
3885 return apair
->klass
== bpair
->klass
&& apair
->method
== bpair
->method
? 1 : 0;
3889 class_method_pair_hash (gconstpointer data
)
3891 const MonoClassMethodPair
*pair
= (const MonoClassMethodPair
*)data
;
3893 return (gsize
)pair
->klass
^ (gsize
)pair
->method
;
3897 mini_create_jit_domain_info (MonoDomain
*domain
)
3899 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
3901 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3902 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3903 info
->delegate_trampoline_hash
= g_hash_table_new (class_method_pair_hash
, class_method_pair_equal
);
3904 info
->llvm_vcall_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3905 info
->runtime_invoke_hash
= mono_conc_hashtable_new_full (mono_aligned_addr_hash
, NULL
, NULL
, runtime_invoke_info_free
);
3906 info
->seq_points
= g_hash_table_new_full (mono_aligned_addr_hash
, NULL
, NULL
, mono_seq_point_info_free
);
3907 info
->arch_seq_points
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3908 info
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
3909 mono_jit_code_hash_init (&info
->interp_code_hash
);
3911 domain
->runtime_info
= info
;
3915 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
3917 MonoJumpList
*jlist
= (MonoJumpList
*)value
;
3918 g_slist_free ((GSList
*)jlist
->list
);
3922 delete_got_slot_list (gpointer key
, gpointer value
, gpointer user_data
)
3924 GSList
*list
= (GSList
*)value
;
3925 g_slist_free (list
);
3929 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
3931 MonoJitDynamicMethodInfo
*di
= (MonoJitDynamicMethodInfo
*)value
;
3932 mono_code_manager_destroy (di
->code_mp
);
3937 runtime_invoke_info_free (gpointer value
)
3939 RuntimeInvokeInfo
*info
= (RuntimeInvokeInfo
*)value
;
3941 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3942 if (info
->dyn_call_info
)
3943 mono_arch_dyn_call_free (info
->dyn_call_info
);
3949 free_jit_callee_list (gpointer key
, gpointer value
, gpointer user_data
)
3951 g_slist_free ((GSList
*)value
);
3955 mini_free_jit_domain_info (MonoDomain
*domain
)
3957 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3959 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
3960 g_hash_table_destroy (info
->jump_target_hash
);
3961 if (info
->jump_target_got_slot_hash
) {
3962 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_got_slot_list
, NULL
);
3963 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
3965 if (info
->dynamic_code_hash
) {
3966 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
3967 g_hash_table_destroy (info
->dynamic_code_hash
);
3969 g_hash_table_destroy (info
->method_code_hash
);
3970 g_hash_table_destroy (info
->jump_trampoline_hash
);
3971 g_hash_table_destroy (info
->jit_trampoline_hash
);
3972 g_hash_table_destroy (info
->delegate_trampoline_hash
);
3973 g_hash_table_destroy (info
->static_rgctx_trampoline_hash
);
3974 g_hash_table_destroy (info
->mrgctx_hash
);
3975 g_hash_table_destroy (info
->method_rgctx_hash
);
3976 g_hash_table_destroy (info
->interp_method_pointer_hash
);
3977 g_hash_table_destroy (info
->llvm_vcall_trampoline_hash
);
3978 mono_conc_hashtable_destroy (info
->runtime_invoke_hash
);
3979 g_hash_table_destroy (info
->seq_points
);
3980 g_hash_table_destroy (info
->arch_seq_points
);
3981 if (info
->agent_info
)
3982 mini_get_dbg_callbacks ()->free_domain_info (domain
);
3983 g_hash_table_destroy (info
->gsharedvt_arg_tramp_hash
);
3984 if (info
->llvm_jit_callees
) {
3985 g_hash_table_foreach (info
->llvm_jit_callees
, free_jit_callee_list
, NULL
);
3986 g_hash_table_destroy (info
->llvm_jit_callees
);
3988 mono_internal_hash_table_destroy (&info
->interp_code_hash
);
3990 mono_llvm_free_domain_info (domain
);
3993 g_free (domain
->runtime_info
);
3994 domain
->runtime_info
= NULL
;
3997 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4000 code_manager_chunk_new (void *chunk
, int size
)
4002 mono_arch_code_chunk_new (chunk
, size
);
4006 code_manager_chunk_destroy (void *chunk
)
4008 mono_arch_code_chunk_destroy (chunk
);
4015 llvm_init_inner (void)
4017 if (!mono_llvm_load (NULL
))
4028 * Load and initialize LLVM support.
4029 * Return TRUE on success.
4032 mini_llvm_init (void)
4035 static gboolean llvm_inited
;
4036 static gboolean init_result
;
4038 mono_loader_lock_if_inited ();
4040 init_result
= llvm_init_inner ();
4043 mono_loader_unlock_if_inited ();
4051 mini_add_profiler_argument (const char *desc
)
4053 if (!profile_options
)
4054 profile_options
= g_ptr_array_new ();
4056 g_ptr_array_add (profile_options
, (gpointer
) desc
);
4060 static MonoEECallbacks interp_cbs
= {0};
4063 mini_install_interp_callbacks (MonoEECallbacks
*cbs
)
4065 memcpy (&interp_cbs
, cbs
, sizeof (MonoEECallbacks
));
4069 mini_get_interp_callbacks (void)
4074 static MonoDebuggerCallbacks dbg_cbs
;
4077 mini_install_dbg_callbacks (MonoDebuggerCallbacks
*cbs
)
4079 g_assert (cbs
->version
== MONO_DBG_CALLBACKS_VERSION
);
4080 memcpy (&dbg_cbs
, cbs
, sizeof (MonoDebuggerCallbacks
));
4083 MonoDebuggerCallbacks
*
4084 mini_get_dbg_callbacks (void)
4090 mono_ee_api_version (void)
4092 return MONO_EE_API_VERSION
;
4096 mono_interp_entry_from_trampoline (gpointer ccontext
, gpointer imethod
)
4098 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext
, imethod
);
4102 mono_interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
4104 mini_get_interp_callbacks ()->to_native_trampoline (addr
, ccontext
);
4108 mini_init (const char *filename
, const char *runtime_version
)
4112 MonoRuntimeCallbacks callbacks
;
4113 MonoThreadInfoRuntimeCallbacks ticallbacks
;
4114 MonoCodeManagerCallbacks code_manager_callbacks
;
4116 MONO_VES_INIT_BEGIN ();
4118 CHECKED_MONO_INIT ();
4120 #if defined(__linux__)
4121 if (access ("/proc/self/maps", F_OK
) != 0) {
4122 g_print ("Mono requires /proc to be mounted.\n");
4127 mono_interp_stub_init ();
4128 #ifndef DISABLE_INTERPRETER
4129 if (mono_use_interpreter
)
4130 mono_ee_interp_init (mono_interp_opts_string
);
4133 mono_debugger_agent_stub_init ();
4135 mono_debugger_agent_init ();
4139 mini_get_dbg_callbacks ()->parse_options (sdb_options
);
4141 mono_os_mutex_init_recursive (&jit_mutex
);
4143 mono_cross_helpers_run ();
4145 mono_counters_init ();
4149 mini_jit_init_job_control ();
4151 /* Happens when using the embedding interface */
4152 if (!default_opt_set
)
4153 default_opt
= mono_parse_default_optimizations (NULL
);
4155 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4157 mono_set_generic_sharing_vt_supported (TRUE
);
4160 mono_set_generic_sharing_vt_supported (TRUE
);
4163 mono_tls_init_runtime_keys ();
4165 if (!global_codeman
)
4166 global_codeman
= mono_code_manager_new ();
4168 memset (&callbacks
, 0, sizeof (callbacks
));
4169 callbacks
.create_ftnptr
= mini_create_ftnptr
;
4170 callbacks
.get_addr_from_ftnptr
= mini_get_addr_from_ftnptr
;
4171 callbacks
.get_runtime_build_info
= mono_get_runtime_build_info
;
4172 callbacks
.set_cast_details
= mono_set_cast_details
;
4173 callbacks
.debug_log
= mini_get_dbg_callbacks ()->debug_log
;
4174 callbacks
.debug_log_is_enabled
= mini_get_dbg_callbacks ()->debug_log_is_enabled
;
4175 callbacks
.get_vtable_trampoline
= mini_get_vtable_trampoline
;
4176 callbacks
.get_imt_trampoline
= mini_get_imt_trampoline
;
4177 callbacks
.imt_entry_inited
= mini_imt_entry_inited
;
4178 callbacks
.init_delegate
= mini_init_delegate
;
4179 #define JIT_INVOKE_WORKS
4180 #ifdef JIT_INVOKE_WORKS
4181 callbacks
.runtime_invoke
= mono_jit_runtime_invoke
;
4183 #define JIT_TRAMPOLINES_WORK
4184 #ifdef JIT_TRAMPOLINES_WORK
4185 callbacks
.compile_method
= mono_jit_compile_method
;
4186 callbacks
.create_jump_trampoline
= mono_create_jump_trampoline
;
4187 callbacks
.create_jit_trampoline
= mono_create_jit_trampoline
;
4188 callbacks
.create_delegate_trampoline
= mono_create_delegate_trampoline
;
4189 callbacks
.free_method
= mono_jit_free_method
;
4190 #ifndef DISABLE_REMOTING
4191 callbacks
.create_remoting_trampoline
= mono_jit_create_remoting_trampoline
;
4194 #ifndef DISABLE_REMOTING
4195 if (mono_use_interpreter
)
4196 callbacks
.interp_get_remoting_invoke
= mini_get_interp_callbacks ()->get_remoting_invoke
;
4198 callbacks
.get_weak_field_indexes
= mono_aot_get_weak_field_indexes
;
4200 #ifndef DISABLE_CRASH_REPORTING
4201 callbacks
.install_state_summarizer
= mini_register_sigterm_handler
;
4204 mono_install_callbacks (&callbacks
);
4206 memset (&ticallbacks
, 0, sizeof (ticallbacks
));
4207 ticallbacks
.setup_async_callback
= mono_setup_async_callback
;
4208 ticallbacks
.thread_state_init_from_sigctx
= mono_thread_state_init_from_sigctx
;
4209 ticallbacks
.thread_state_init_from_handle
= mono_thread_state_init_from_handle
;
4210 ticallbacks
.thread_state_init
= mono_thread_state_init
;
4213 mono_w32handle_init ();
4216 mono_thread_info_runtime_init (&ticallbacks
);
4218 if (g_hasenv ("MONO_DEBUG")) {
4219 mini_parse_debug_options ();
4222 mono_code_manager_init ();
4224 memset (&code_manager_callbacks
, 0, sizeof (code_manager_callbacks
));
4225 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4226 code_manager_callbacks
.chunk_new
= code_manager_chunk_new
;
4227 code_manager_callbacks
.chunk_destroy
= code_manager_chunk_destroy
;
4229 mono_code_manager_install_callbacks (&code_manager_callbacks
);
4233 mono_arch_cpu_init ();
4237 mono_unwind_init ();
4239 if (mini_get_debug_options ()->lldb
|| g_hasenv ("MONO_LLDB")) {
4240 mono_lldb_init ("");
4241 mono_dont_free_domains
= TRUE
;
4244 #ifdef XDEBUG_ENABLED
4245 char *mono_xdebug
= g_getenv ("MONO_XDEBUG");
4247 mono_xdebug_init (mono_xdebug
);
4248 g_free (mono_xdebug
);
4249 /* So methods for multiple domains don't have the same address */
4250 mono_dont_free_domains
= TRUE
;
4251 mono_using_xdebug
= TRUE
;
4252 } else if (mini_get_debug_options ()->gdb
) {
4253 mono_xdebug_init ((char*)"gdb");
4254 mono_dont_free_domains
= TRUE
;
4255 mono_using_xdebug
= TRUE
;
4260 if (mono_use_llvm
) {
4261 if (!mono_llvm_load (NULL
)) {
4262 mono_use_llvm
= FALSE
;
4263 fprintf (stderr
, "Mono Warning: llvm support could not be loaded.\n");
4270 mono_trampolines_init ();
4272 if (default_opt
& MONO_OPT_AOT
)
4275 mini_get_dbg_callbacks ()->init ();
4278 mono_wasm_debugger_init ();
4281 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4282 mono_set_generic_sharing_supported (TRUE
);
4285 mono_thread_info_signals_init ();
4287 #ifndef MONO_CROSS_COMPILE
4288 mono_runtime_install_handlers ();
4290 mono_threads_install_cleanup (mini_thread_cleanup
);
4292 #ifdef JIT_TRAMPOLINES_WORK
4293 mono_install_create_domain_hook (mini_create_jit_domain_info
);
4294 mono_install_free_domain_hook (mini_free_jit_domain_info
);
4296 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
4297 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
4298 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
4300 mono_profiler_state
.context_enable
= mini_profiler_context_enable
;
4301 mono_profiler_state
.context_get_this
= mini_profiler_context_get_this
;
4302 mono_profiler_state
.context_get_argument
= mini_profiler_context_get_argument
;
4303 mono_profiler_state
.context_get_local
= mini_profiler_context_get_local
;
4304 mono_profiler_state
.context_get_result
= mini_profiler_context_get_result
;
4305 mono_profiler_state
.context_free_buffer
= mini_profiler_context_free_buffer
;
4307 if (profile_options
)
4308 for (guint i
= 0; i
< profile_options
->len
; i
++)
4309 mono_profiler_load ((const char *) g_ptr_array_index (profile_options
, i
));
4311 mono_profiler_started ();
4313 if (mini_debug_options
.collect_pagefault_stats
)
4314 mono_aot_set_make_unreadable (TRUE
);
4316 if (runtime_version
)
4317 domain
= mono_init_version (filename
, runtime_version
);
4319 domain
= mono_init_from_assembly (filename
, filename
);
4321 if (mono_aot_only
) {
4322 /* This helps catch code allocation requests */
4323 mono_code_manager_set_read_only (domain
->code_mp
);
4324 mono_marshal_use_aot_wrappers (TRUE
);
4327 if (mono_llvm_only
) {
4328 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline
);
4329 mono_set_always_build_imt_trampolines (TRUE
);
4330 } else if (mono_aot_only
) {
4331 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline
);
4333 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline
);
4336 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4337 mono_arch_finish_init ();
4339 /* This must come after mono_init () in the aot-only case */
4340 mono_exceptions_init ();
4342 /* This should come after mono_init () too */
4346 mono_create_helper_signatures ();
4349 register_jit_stats ();
4351 #define JIT_CALLS_WORK
4352 #ifdef JIT_CALLS_WORK
4353 /* Needs to be called here since register_jit_icall depends on it */
4354 mono_marshal_init ();
4356 mono_arch_register_lowlevel_calls ();
4360 mono_generic_sharing_init ();
4363 #ifdef MONO_ARCH_SIMD_INTRINSICS
4364 mono_simd_intrinsics_init ();
4367 mono_tasklets_init ();
4369 register_trampolines (domain
);
4371 if (mono_compile_aot
)
4373 * Avoid running managed code when AOT compiling, since the platform
4374 * might only support aot-only execution.
4376 mono_runtime_set_no_exec (TRUE
);
4378 mono_mem_account_register_counters ();
4380 #define JIT_RUNTIME_WORKS
4381 #ifdef JIT_RUNTIME_WORKS
4382 #ifndef DISABLE_CLEANUP
4383 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
4385 mono_runtime_init_checked (domain
, (MonoThreadStartCB
)mono_thread_start_cb
, mono_thread_attach_cb
, error
);
4386 mono_error_assert_ok (error
);
4387 mono_thread_attach (domain
);
4388 MONO_PROFILER_RAISE (thread_name
, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4391 if (mono_profiler_sampling_enabled ())
4392 mono_runtime_setup_stat_profiler ();
4394 MONO_PROFILER_RAISE (runtime_initialized
, ());
4396 MONO_VES_INIT_END ();
4401 #ifdef MONO_ARCH_EMULATE_FREM
4402 // Wrapper to avoid taking address of overloaded function.
4404 mono_fmod (double a
, double b
)
4411 register_icalls (void)
4413 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4414 ves_icall_get_frame_info
);
4415 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4416 ves_icall_get_trace
);
4417 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4418 mono_runtime_install_handlers
);
4419 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4420 mono_runtime_cleanup_handlers
);
4422 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4423 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4424 mini_get_dbg_callbacks ()->unhandled_exception
);
4428 * It's important that we pass `TRUE` as the last argument here, as
4429 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4430 * *did* emit a wrapper, we'd be looking at infinite recursion since
4431 * the wrapper would call the icall which would call the wrapper and
4434 register_icall (mono_profiler_raise_method_enter
, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE
);
4435 register_icall (mono_profiler_raise_method_leave
, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE
);
4436 register_icall (mono_profiler_raise_method_tail_call
, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE
);
4437 register_icall (mono_profiler_raise_exception_clause
, "mono_profiler_raise_exception_clause", "void ptr int int object", TRUE
);
4439 register_icall (mono_trace_enter_method
, "mono_trace_enter_method", "void ptr ptr", TRUE
);
4440 register_icall (mono_trace_leave_method
, "mono_trace_leave_method", "void ptr ptr", TRUE
);
4441 register_icall (mono_get_lmf_addr
, "mono_get_lmf_addr", "ptr", TRUE
);
4442 register_icall (mono_jit_set_domain
, "mono_jit_set_domain", "void ptr", TRUE
);
4443 register_icall (mono_domain_get
, "mono_domain_get", "ptr", TRUE
);
4445 register_icall (mono_llvm_throw_exception
, "mono_llvm_throw_exception", "void object", TRUE
);
4446 register_icall (mono_llvm_rethrow_exception
, "mono_llvm_rethrow_exception", "void object", TRUE
);
4447 register_icall (mono_llvm_resume_exception
, "mono_llvm_resume_exception", "void", TRUE
);
4448 register_icall (mono_llvm_match_exception
, "mono_llvm_match_exception", "int ptr int int ptr object", TRUE
);
4449 register_icall (mono_llvm_clear_exception
, "mono_llvm_clear_exception", NULL
, TRUE
);
4450 register_icall (mono_llvm_load_exception
, "mono_llvm_load_exception", "object", TRUE
);
4451 register_icall (mono_llvm_throw_corlib_exception
, "mono_llvm_throw_corlib_exception", "void int", TRUE
);
4452 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4453 register_icall (mono_llvm_set_unhandled_exception_handler
, "mono_llvm_set_unhandled_exception_handler", NULL
, TRUE
);
4455 // FIXME: This is broken
4456 register_icall (mono_debug_personality
, "mono_debug_personality", "int int int ptr ptr ptr", TRUE
);
4459 if (!mono_llvm_only
) {
4460 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE
);
4461 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE
);
4462 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE
);
4464 register_icall (mono_thread_get_undeniable_exception
, "mono_thread_get_undeniable_exception", "object", FALSE
);
4465 register_icall (ves_icall_thread_finish_async_abort
, "ves_icall_thread_finish_async_abort", "void", FALSE
);
4466 register_icall (mono_thread_interruption_checkpoint
, "mono_thread_interruption_checkpoint", "object", FALSE
);
4467 register_icall (mono_thread_force_interruption_checkpoint_noraise
, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE
);
4469 register_icall (mono_threads_state_poll
, "mono_threads_state_poll", "void", FALSE
);
4471 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4472 register_opcode_emulation (OP_LMUL
, "__emul_lmul", "long long long", mono_llmult
, "mono_llmult", FALSE
);
4473 register_opcode_emulation (OP_LDIV
, "__emul_ldiv", "long long long", mono_lldiv
, "mono_lldiv", FALSE
);
4474 register_opcode_emulation (OP_LDIV_UN
, "__emul_ldiv_un", "long long long", mono_lldiv_un
, "mono_lldiv_un", FALSE
);
4475 register_opcode_emulation (OP_LREM
, "__emul_lrem", "long long long", mono_llrem
, "mono_llrem", FALSE
);
4476 register_opcode_emulation (OP_LREM_UN
, "__emul_lrem_un", "long long long", mono_llrem_un
, "mono_llrem_un", FALSE
);
4478 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4479 register_opcode_emulation (OP_LMUL_OVF_UN
, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un
, "mono_llmult_ovf_un", FALSE
);
4480 register_opcode_emulation (OP_LMUL_OVF
, "__emul_lmul_ovf", "long long long", mono_llmult_ovf
, "mono_llmult_ovf", FALSE
);
4483 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4484 register_opcode_emulation (OP_LSHL
, "__emul_lshl", "long long int32", mono_lshl
, "mono_lshl", TRUE
);
4485 register_opcode_emulation (OP_LSHR
, "__emul_lshr", "long long int32", mono_lshr
, "mono_lshr", TRUE
);
4486 register_opcode_emulation (OP_LSHR_UN
, "__emul_lshr_un", "long long int32", mono_lshr_un
, "mono_lshr_un", TRUE
);
4489 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4490 register_opcode_emulation (OP_IDIV
, "__emul_op_idiv", "int32 int32 int32", mono_idiv
, "mono_idiv", FALSE
);
4491 register_opcode_emulation (OP_IDIV_UN
, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un
, "mono_idiv_un", FALSE
);
4492 register_opcode_emulation (OP_IREM
, "__emul_op_irem", "int32 int32 int32", mono_irem
, "mono_irem", FALSE
);
4493 register_opcode_emulation (OP_IREM_UN
, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un
, "mono_irem_un", FALSE
);
4496 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4497 register_opcode_emulation (OP_IMUL
, "__emul_op_imul", "int32 int32 int32", mono_imul
, "mono_imul", TRUE
);
4500 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4501 register_opcode_emulation (OP_IMUL_OVF
, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf
, "mono_imul_ovf", FALSE
);
4502 register_opcode_emulation (OP_IMUL_OVF_UN
, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un
, "mono_imul_ovf_un", FALSE
);
4505 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4506 register_opcode_emulation (OP_FDIV
, "__emul_fdiv", "double double double", mono_fdiv
, "mono_fdiv", FALSE
);
4509 register_opcode_emulation (OP_FCONV_TO_U8
, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8_2
, "mono_fconv_u8_2", FALSE
);
4510 register_opcode_emulation (OP_RCONV_TO_U8
, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8
, "mono_rconv_u8", FALSE
);
4511 register_opcode_emulation (OP_FCONV_TO_U4
, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4_2
, "mono_fconv_u4_2", FALSE
);
4512 register_opcode_emulation (OP_FCONV_TO_OVF_I8
, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8
, "mono_fconv_ovf_i8", FALSE
);
4513 register_opcode_emulation (OP_FCONV_TO_OVF_U8
, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8
, "mono_fconv_ovf_u8", FALSE
);
4514 register_opcode_emulation (OP_RCONV_TO_OVF_I8
, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8
, "mono_rconv_ovf_i8", FALSE
);
4515 register_opcode_emulation (OP_RCONV_TO_OVF_U8
, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8
, "mono_rconv_ovf_u8", FALSE
);
4518 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4519 register_opcode_emulation (OP_FCONV_TO_I8
, "__emul_fconv_to_i8", "long double", mono_fconv_i8
, "mono_fconv_i8", FALSE
);
4520 register_opcode_emulation (OP_RCONV_TO_I8
, "__emul_rconv_to_i8", "long float", mono_rconv_i8
, "mono_rconv_i8", FALSE
);
4523 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4524 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
);
4526 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4527 register_opcode_emulation (OP_LCONV_TO_R8
, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8
, "mono_lconv_to_r8", FALSE
);
4529 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4530 register_opcode_emulation (OP_LCONV_TO_R4
, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4
, "mono_lconv_to_r4", FALSE
);
4532 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4533 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
);
4535 #ifdef MONO_ARCH_EMULATE_FREM
4536 register_opcode_emulation (OP_FREM
, "__emul_frem", "double double double", mono_fmod
, "fmod", FALSE
);
4537 register_opcode_emulation (OP_RREM
, "__emul_rrem", "float float float", fmodf
, "fmodf", FALSE
);
4540 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4541 if (mono_arch_is_soft_float ()) {
4542 register_opcode_emulation (OP_FSUB
, "__emul_fsub", "double double double", mono_fsub
, "mono_fsub", FALSE
);
4543 register_opcode_emulation (OP_FADD
, "__emul_fadd", "double double double", mono_fadd
, "mono_fadd", FALSE
);
4544 register_opcode_emulation (OP_FMUL
, "__emul_fmul", "double double double", mono_fmul
, "mono_fmul", FALSE
);
4545 register_opcode_emulation (OP_FNEG
, "__emul_fneg", "double double", mono_fneg
, "mono_fneg", FALSE
);
4546 register_opcode_emulation (OP_ICONV_TO_R8
, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8
, "mono_conv_to_r8", FALSE
);
4547 register_opcode_emulation (OP_ICONV_TO_R4
, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4
, "mono_conv_to_r4", FALSE
);
4548 register_opcode_emulation (OP_FCONV_TO_R4
, "__emul_fconv_to_r4", "double double", mono_fconv_r4
, "mono_fconv_r4", FALSE
);
4549 register_opcode_emulation (OP_FCONV_TO_I1
, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1
, "mono_fconv_i1", FALSE
);
4550 register_opcode_emulation (OP_FCONV_TO_I2
, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2
, "mono_fconv_i2", FALSE
);
4551 register_opcode_emulation (OP_FCONV_TO_I4
, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4552 register_opcode_emulation (OP_FCONV_TO_U1
, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1
, "mono_fconv_u1", FALSE
);
4553 register_opcode_emulation (OP_FCONV_TO_U2
, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2
, "mono_fconv_u2", FALSE
);
4555 #if TARGET_SIZEOF_VOID_P == 4
4556 register_opcode_emulation (OP_FCONV_TO_I
, "__emul_fconv_to_i", "int32 double", mono_fconv_i4
, "mono_fconv_i4", FALSE
);
4559 register_opcode_emulation (OP_FBEQ
, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq
, "mono_fcmp_eq", FALSE
);
4560 register_opcode_emulation (OP_FBLT
, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt
, "mono_fcmp_lt", FALSE
);
4561 register_opcode_emulation (OP_FBGT
, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt
, "mono_fcmp_gt", FALSE
);
4562 register_opcode_emulation (OP_FBLE
, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le
, "mono_fcmp_le", FALSE
);
4563 register_opcode_emulation (OP_FBGE
, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge
, "mono_fcmp_ge", FALSE
);
4564 register_opcode_emulation (OP_FBNE_UN
, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un
, "mono_fcmp_ne_un", FALSE
);
4565 register_opcode_emulation (OP_FBLT_UN
, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un
, "mono_fcmp_lt_un", FALSE
);
4566 register_opcode_emulation (OP_FBGT_UN
, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un
, "mono_fcmp_gt_un", FALSE
);
4567 register_opcode_emulation (OP_FBLE_UN
, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un
, "mono_fcmp_le_un", FALSE
);
4568 register_opcode_emulation (OP_FBGE_UN
, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un
, "mono_fcmp_ge_un", FALSE
);
4570 register_opcode_emulation (OP_FCEQ
, "__emul_fcmp_ceq", "uint32 double double", mono_fceq
, "mono_fceq", FALSE
);
4571 register_opcode_emulation (OP_FCGT
, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt
, "mono_fcgt", FALSE
);
4572 register_opcode_emulation (OP_FCGT_UN
, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un
, "mono_fcgt_un", FALSE
);
4573 register_opcode_emulation (OP_FCLT
, "__emul_fcmp_clt", "uint32 double double", mono_fclt
, "mono_fclt", FALSE
);
4574 register_opcode_emulation (OP_FCLT_UN
, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un
, "mono_fclt_un", FALSE
);
4576 register_icall (mono_fload_r4
, "mono_fload_r4", "double ptr", FALSE
);
4577 register_icall (mono_fstore_r4
, "mono_fstore_r4", "void double ptr", FALSE
);
4578 register_icall (mono_fload_r4_arg
, "mono_fload_r4_arg", "uint32 double", FALSE
);
4579 register_icall (mono_isfinite_double
, "mono_isfinite_double", "int32 double", FALSE
);
4582 register_icall (mono_ckfinite
, "mono_ckfinite", "double double", FALSE
);
4584 #ifdef COMPRESSED_INTERFACE_BITMAP
4585 register_icall (mono_class_interface_match
, "mono_class_interface_match", "uint32 ptr int32", TRUE
);
4588 #if SIZEOF_REGISTER == 4
4589 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4
, "mono_fconv_u4", TRUE
);
4591 register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "ulong double", mono_fconv_u8
, "mono_fconv_u8", TRUE
);
4594 /* other jit icalls */
4595 register_icall (ves_icall_mono_delegate_ctor
, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE
);
4596 register_icall (ves_icall_mono_delegate_ctor_interp
, "ves_icall_mono_delegate_ctor_interp", "void object object ptr", FALSE
);
4597 register_icall (mono_class_static_field_address
, "mono_class_static_field_address",
4598 "ptr ptr ptr", FALSE
);
4599 register_icall (mono_ldtoken_wrapper
, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE
);
4600 register_icall (mono_ldtoken_wrapper_generic_shared
, "mono_ldtoken_wrapper_generic_shared",
4601 "ptr ptr ptr ptr", FALSE
);
4602 register_icall (mono_get_special_static_data
, "mono_get_special_static_data", "ptr int", FALSE
);
4603 register_icall (ves_icall_mono_ldstr
, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE
);
4604 register_icall (mono_helper_stelem_ref_check
, "mono_helper_stelem_ref_check", "void object object", FALSE
);
4605 register_icall (ves_icall_object_new
, "ves_icall_object_new", "object ptr ptr", FALSE
);
4606 register_icall (ves_icall_object_new_specific
, "ves_icall_object_new_specific", "object ptr", FALSE
);
4607 register_icall (ves_icall_array_new
, "ves_icall_array_new", "object ptr ptr int32", FALSE
);
4608 register_icall (ves_icall_array_new_specific
, "ves_icall_array_new_specific", "object ptr int32", FALSE
);
4609 register_icall (ves_icall_runtime_class_init
, "ves_icall_runtime_class_init", "void ptr", FALSE
);
4610 register_icall (mono_ldftn
, "mono_ldftn", "ptr ptr", FALSE
);
4611 register_icall (mono_ldvirtfn
, "mono_ldvirtfn", "ptr object ptr", FALSE
);
4612 register_icall (mono_ldvirtfn_gshared
, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE
);
4613 register_icall (mono_helper_compile_generic_method
, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE
);
4614 register_icall (mono_helper_ldstr
, "mono_helper_ldstr", "object ptr int", FALSE
);
4615 register_icall (mono_helper_ldstr_mscorlib
, "mono_helper_ldstr_mscorlib", "object int", FALSE
);
4616 register_icall (mono_helper_newobj_mscorlib
, "mono_helper_newobj_mscorlib", "object int", FALSE
);
4617 register_icall (mono_value_copy_internal
, "mono_value_copy_internal", "void ptr ptr ptr", FALSE
);
4618 register_icall (mono_object_castclass_unbox
, "mono_object_castclass_unbox", "object object ptr", FALSE
);
4619 register_icall (mono_break
, "mono_break", NULL
, TRUE
);
4620 register_icall (mono_create_corlib_exception_0
, "mono_create_corlib_exception_0", "object int", TRUE
);
4621 register_icall (mono_create_corlib_exception_1
, "mono_create_corlib_exception_1", "object int object", TRUE
);
4622 register_icall (mono_create_corlib_exception_2
, "mono_create_corlib_exception_2", "object int object object", TRUE
);
4623 register_icall (mono_array_new_1
, "mono_array_new_1", "object ptr int", FALSE
);
4624 register_icall (mono_array_new_2
, "mono_array_new_2", "object ptr int int", FALSE
);
4625 register_icall (mono_array_new_3
, "mono_array_new_3", "object ptr int int int", FALSE
);
4626 register_icall (mono_array_new_4
, "mono_array_new_4", "object ptr int int int int", FALSE
);
4627 register_icall (mono_array_new_n_icall
, "mono_array_new_n_icall", "object ptr int ptr", FALSE
);
4628 register_icall (mono_get_native_calli_wrapper
, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE
);
4629 register_icall (mono_resume_unwind
, "mono_resume_unwind", "void ptr", TRUE
);
4630 register_icall (mono_gsharedvt_constrained_call
, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE
);
4631 register_icall (mono_gsharedvt_value_copy
, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE
);
4633 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4634 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4636 register_icall (mono_object_castclass_with_cache
, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE
);
4637 register_icall (mono_object_isinst_with_cache
, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE
);
4638 register_icall (mono_generic_class_init
, "mono_generic_class_init", "void ptr", FALSE
);
4639 register_icall (mono_fill_class_rgctx
, "mono_fill_class_rgctx", "ptr ptr int", FALSE
);
4640 register_icall (mono_fill_method_rgctx
, "mono_fill_method_rgctx", "ptr ptr int", FALSE
);
4642 register_dyn_icall (mini_get_dbg_callbacks ()->user_break
, "mono_debugger_agent_user_break", "void", FALSE
);
4644 register_icall (mono_aot_init_llvm_method
, "mono_aot_init_llvm_method", "void ptr int", TRUE
);
4645 register_icall (mono_aot_init_gshared_method_this
, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE
);
4646 register_icall (mono_aot_init_gshared_method_mrgctx
, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE
);
4647 register_icall (mono_aot_init_gshared_method_vtable
, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE
);
4649 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt
, "mini_llvmonly_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4650 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt
, "mini_llvmonly_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4651 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call
, "mini_llvmonly_resolve_generic_virtual_call", "ptr ptr int ptr");
4652 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call
, "mini_llvmonly_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4653 /* This needs a wrapper so it can have a preserveall cconv */
4654 register_icall (mini_llvmonly_init_vtable_slot
, "mini_llvmonly_init_vtable_slot", "ptr ptr int", FALSE
);
4655 register_icall (mini_llvmonly_init_delegate
, "mini_llvmonly_init_delegate", "void object", TRUE
);
4656 register_icall (mini_llvmonly_init_delegate_virtual
, "mini_llvmonly_init_delegate_virtual", "void object object ptr", TRUE
);
4658 register_icall (mono_get_assembly_object
, "mono_get_assembly_object", "object ptr", TRUE
);
4659 register_icall (mono_get_method_object
, "mono_get_method_object", "object ptr", TRUE
);
4660 register_icall (mono_throw_method_access
, "mono_throw_method_access", "void ptr ptr", FALSE
);
4661 register_icall_no_wrapper (mono_dummy_jit_icall
, "mono_dummy_jit_icall", "void");
4663 register_icall_with_wrapper (mono_monitor_enter_internal
, "mono_monitor_enter_internal", "int32 obj");
4664 register_icall_with_wrapper (mono_monitor_enter_v4_internal
, "mono_monitor_enter_v4_internal", "void obj ptr");
4665 register_icall_no_wrapper (mono_monitor_enter_fast
, "mono_monitor_enter_fast", "int obj");
4666 register_icall_no_wrapper (mono_monitor_enter_v4_fast
, "mono_monitor_enter_v4_fast", "int obj ptr");
4669 register_icall (pthread_getspecific
, "pthread_getspecific", "ptr ptr", TRUE
);
4671 /* Register tls icalls */
4672 register_icall_no_wrapper (mono_tls_get_thread
, "mono_tls_get_thread", "ptr");
4673 register_icall_no_wrapper (mono_tls_get_jit_tls
, "mono_tls_get_jit_tls", "ptr");
4674 register_icall_no_wrapper (mono_tls_get_domain
, "mono_tls_get_domain", "ptr");
4675 register_icall_no_wrapper (mono_tls_get_sgen_thread_info
, "mono_tls_get_sgen_thread_info", "ptr");
4676 register_icall_no_wrapper (mono_tls_get_lmf_addr
, "mono_tls_get_lmf_addr", "ptr");
4677 register_icall_no_wrapper (mono_tls_set_thread
, "mono_tls_set_thread", "void ptr");
4678 register_icall_no_wrapper (mono_tls_set_jit_tls
, "mono_tls_set_jit_tls", "void ptr");
4679 register_icall_no_wrapper (mono_tls_set_domain
, "mono_tls_set_domain", "void ptr");
4680 register_icall_no_wrapper (mono_tls_set_sgen_thread_info
, "mono_tls_set_sgen_thread_info", "void ptr");
4681 register_icall_no_wrapper (mono_tls_set_lmf_addr
, "mono_tls_set_lmf_addr", "void ptr");
4683 register_icall_no_wrapper (mono_interp_entry_from_trampoline
, "mono_interp_entry_from_trampoline", "void ptr ptr");
4684 register_icall_no_wrapper (mono_interp_to_native_trampoline
, "mono_interp_to_native_trampoline", "void ptr ptr");
4686 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4687 mono_arch_register_icall ();
4691 MonoJitStats mono_jit_stats
= {0};
4694 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4695 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4697 MONO_NO_SANITIZE_THREAD
4699 print_jit_stats (void)
4701 if (mono_jit_stats
.enabled
) {
4702 g_print ("Mono Jit statistics\n");
4703 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/ 100.0,
4704 mono_jit_stats
.max_ratio_method
);
4705 g_print ("Biggest method: %" G_GINT32_FORMAT
" (%s)\n", mono_jit_stats
.biggest_method_size
,
4706 mono_jit_stats
.biggest_method
);
4708 g_print ("Delegates created: %" G_GINT32_FORMAT
"\n", mono_stats
.delegate_creations
);
4709 g_print ("Initialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.initialized_class_count
);
4710 g_print ("Used classes: %" G_GINT32_FORMAT
"\n", mono_stats
.used_class_count
);
4711 g_print ("Generic vtables: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_vtable_count
);
4712 g_print ("Methods: %" G_GINT32_FORMAT
"\n", mono_stats
.method_count
);
4713 g_print ("Static data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_static_data_size
);
4714 g_print ("VTable data size: %" G_GINT32_FORMAT
"\n", mono_stats
.class_vtable_size
);
4715 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4717 g_print ("\nInitialized classes: %" G_GINT32_FORMAT
"\n", mono_stats
.generic_class_count
);
4718 g_print ("Inflated types: %" G_GINT32_FORMAT
"\n", mono_stats
.inflated_type_count
);
4719 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4721 g_print ("Sharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_sharable_methods
);
4722 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_unsharable_methods
);
4723 g_print ("Shared generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.generics_shared_methods
);
4724 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT
"\n", mono_stats
.gsharedvt_methods
);
4726 g_print ("IMT tables size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_tables_size
);
4727 g_print ("IMT number of tables: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_tables
);
4728 g_print ("IMT number of methods: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_number_of_methods
);
4729 g_print ("IMT used slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_used_slots
);
4730 g_print ("IMT colliding slots: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_slots_with_collisions
);
4731 g_print ("IMT max collisions: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_max_collisions_in_slot
);
4732 g_print ("IMT methods at max col: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_method_count_when_max_collisions
);
4733 g_print ("IMT trampolines size: %" G_GINT32_FORMAT
"\n", mono_stats
.imt_trampolines_size
);
4735 g_print ("JIT info table inserts: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_insert_count
);
4736 g_print ("JIT info table removes: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_remove_count
);
4737 g_print ("JIT info table lookups: %" G_GINT32_FORMAT
"\n", mono_stats
.jit_info_table_lookup_count
);
4739 g_free (mono_jit_stats
.max_ratio_method
);
4740 mono_jit_stats
.max_ratio_method
= NULL
;
4741 g_free (mono_jit_stats
.biggest_method
);
4742 mono_jit_stats
.biggest_method
= NULL
;
4747 mini_cleanup (MonoDomain
*domain
)
4749 if (mono_profiler_sampling_enabled ())
4750 mono_runtime_shutdown_stat_profiler ();
4752 MONO_PROFILER_RAISE (runtime_shutdown_begin
, ());
4755 mono_cominterop_release_all_rcws ();
4758 #ifndef MONO_CROSS_COMPILE
4760 * mono_domain_finalize () needs to be called early since it needs the
4761 * execution engine still fully working (it may invoke managed finalizers).
4763 mono_domain_finalize (domain
, 2000);
4766 /* This accesses metadata so needs to be called before runtime shutdown */
4769 #ifndef MONO_CROSS_COMPILE
4770 mono_runtime_cleanup (domain
);
4773 mono_threadpool_cleanup ();
4775 MONO_PROFILER_RAISE (runtime_shutdown_end
, ());
4777 mono_profiler_cleanup ();
4779 if (profile_options
)
4780 g_ptr_array_free (profile_options
, TRUE
);
4782 free_jit_tls_data (mono_tls_get_jit_tls ());
4784 mono_icall_cleanup ();
4786 mono_runtime_cleanup_handlers ();
4788 #ifndef MONO_CROSS_COMPILE
4789 mono_domain_free (domain
, TRUE
);
4794 mono_llvm_cleanup ();
4797 mono_aot_cleanup ();
4799 mono_trampolines_cleanup ();
4801 mono_unwind_cleanup ();
4803 mono_code_manager_destroy (global_codeman
);
4804 g_free (vtable_trampolines
);
4806 mini_jit_cleanup ();
4808 mono_tramp_info_cleanup ();
4810 mono_arch_cleanup ();
4812 mono_generic_sharing_cleanup ();
4816 mono_trace_cleanup ();
4818 mono_counters_dump (MONO_COUNTER_SECTION_MASK
| MONO_COUNTER_MONOTONIC
, stdout
);
4820 if (mono_inject_async_exc_method
)
4821 mono_method_desc_free (mono_inject_async_exc_method
);
4823 mono_tls_free_keys ();
4825 mono_os_mutex_destroy (&jit_mutex
);
4827 mono_code_manager_cleanup ();
4830 mono_w32handle_cleanup ();
4835 mono_set_defaults (int verbose_level
, guint32 opts
)
4837 mini_verbose
= verbose_level
;
4838 mono_set_optimizations (opts
);
4842 mono_disable_optimizations (guint32 opts
)
4844 default_opt
&= ~opts
;
4848 mono_set_optimizations (guint32 opts
)
4851 default_opt_set
= TRUE
;
4852 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4853 mono_set_generic_sharing_vt_supported (mono_aot_only
|| ((default_opt
& MONO_OPT_GSHAREDVT
) != 0));
4856 mono_set_generic_sharing_vt_supported (TRUE
);
4861 mono_set_verbose_level (guint32 level
)
4863 mini_verbose
= level
;
4867 * mono_get_runtime_build_info:
4868 * The returned string is owned by the caller. The returned string
4869 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4870 * \returns the runtime version + build date in string format.
4873 mono_get_runtime_build_info (void)
4875 if (mono_build_date
)
4876 return g_strdup_printf ("%s (%s %s)", VERSION
, FULL_VERSION
, mono_build_date
);
4878 return g_strdup_printf ("%s (%s)", VERSION
, FULL_VERSION
);
4882 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
4884 GHashTable
*assemblies
= (GHashTable
*)user_data
;
4885 MonoImage
*image
= mono_assembly_get_image_internal (ass
);
4886 MonoMethod
*method
, *invoke
;
4889 if (g_hash_table_lookup (assemblies
, ass
))
4892 g_hash_table_insert (assemblies
, ass
, ass
);
4894 if (mini_verbose
> 0)
4895 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
4897 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
4900 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, error
);
4902 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4905 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
4907 if (method
->is_generic
|| mono_class_is_gtd (method
->klass
))
4911 if (mini_verbose
> 1) {
4912 char * desc
= mono_method_full_name (method
, TRUE
);
4913 g_print ("Compiling %d %s\n", count
, desc
);
4916 mono_compile_method_checked (method
, error
);
4917 if (!is_ok (error
)) {
4918 mono_error_cleanup (error
); /* FIXME don't swallow the error */
4921 if (strcmp (method
->name
, "Finalize") == 0) {
4922 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4923 mono_compile_method_checked (invoke
, error
);
4924 mono_error_assert_ok (error
);
4926 #ifndef DISABLE_REMOTING
4927 if (mono_class_is_marshalbyref (method
->klass
) && mono_method_signature_internal (method
)->hasthis
) {
4928 invoke
= mono_marshal_get_remoting_invoke_with_check (method
, error
);
4929 mono_error_assert_ok (error
);
4930 mono_compile_method_checked (invoke
, error
);
4931 mono_error_assert_ok (error
);
4936 /* Load and precompile referenced assemblies as well */
4937 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
4938 mono_assembly_load_reference (image
, i
);
4939 if (image
->references
[i
])
4940 mono_precompile_assembly (image
->references
[i
], assemblies
);
4944 void mono_precompile_assemblies ()
4946 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
4948 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
4950 g_hash_table_destroy (assemblies
);
4955 * Have to export this for AOT.
4958 mono_personality (void)
4961 g_assert_not_reached ();
4964 static MonoBreakPolicy
4965 always_insert_breakpoint (MonoMethod
*method
)
4967 return MONO_BREAK_POLICY_ALWAYS
;
4970 static MonoBreakPolicyFunc break_policy_func
= always_insert_breakpoint
;
4973 * mono_set_break_policy:
4974 * \param policy_callback the new callback function
4976 * Allow embedders to decide whether to actually obey breakpoint instructions
4977 * (both break IL instructions and \c Debugger.Break method calls), for example
4978 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4979 * untrusted or semi-trusted code.
4981 * \p policy_callback will be called every time a break point instruction needs to
4982 * be inserted with the method argument being the method that calls \c Debugger.Break
4983 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4984 * if it wants the breakpoint to not be effective in the given method.
4985 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4988 mono_set_break_policy (MonoBreakPolicyFunc policy_callback
)
4990 if (policy_callback
)
4991 break_policy_func
= policy_callback
;
4993 break_policy_func
= always_insert_breakpoint
;
4997 mini_should_insert_breakpoint (MonoMethod
*method
)
4999 switch (break_policy_func (method
)) {
5000 case MONO_BREAK_POLICY_ALWAYS
:
5002 case MONO_BREAK_POLICY_NEVER
:
5004 case MONO_BREAK_POLICY_ON_DBG
:
5005 g_warning ("mdb no longer supported");
5008 g_warning ("Incorrect value returned from break policy callback");
5013 // Custom handlers currently only implemented by Windows.
5016 mono_runtime_install_custom_handlers (const char *handlers
)
5022 mono_runtime_install_custom_handlers_usage (void)
5025 "Custom Handlers:\n"
5026 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5027 " separated list of available handlers to install.\n"
5029 "No handlers supported on current platform.\n");
5031 #endif /* HOST_WIN32 */