Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / mini / mini-runtime.c
blobdd6f0e968fa59ed1a271662aab03b15b859e4b2b
1 /**
2 * \file
3 * Runtime code for the JIT
5 * Authors:
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.
15 #include <config.h>
16 #ifdef HAVE_ALLOCA_H
17 #include <alloca.h>
18 #endif
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22 #include <math.h>
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #include <signal.h>
28 #include <mono/utils/memcheck.h>
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/assembly-internals.h>
32 #include <mono/metadata/loader.h>
33 #include <mono/metadata/tabledefs.h>
34 #include <mono/metadata/class.h>
35 #include <mono/metadata/object.h>
36 #include <mono/metadata/tokentype.h>
37 #include <mono/metadata/tabledefs.h>
38 #include <mono/metadata/threads.h>
39 #include <mono/metadata/appdomain.h>
40 #include <mono/metadata/debug-helpers.h>
41 #include <mono/metadata/domain-internals.h>
42 #include <mono/metadata/profiler-private.h>
43 #include <mono/metadata/mono-config.h>
44 #include <mono/metadata/environment.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/threads-types.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/runtime.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/metadata/icall-internals.h>
54 #include <mono/metadata/loader-internals.h>
55 #define MONO_MATH_DECLARE_ALL 1
56 #include <mono/utils/mono-math.h>
57 #include <mono/utils/mono-compiler.h>
58 #include <mono/utils/mono-counters.h>
59 #include <mono/utils/mono-error-internals.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-mmap.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-tls.h>
64 #include <mono/utils/mono-hwcap.h>
65 #include <mono/utils/dtrace.h>
66 #include <mono/utils/mono-signal-handler.h>
67 #include <mono/utils/mono-threads.h>
68 #include <mono/utils/mono-threads-coop.h>
69 #include <mono/utils/checked-build.h>
70 #include <mono/utils/mono-compiler.h>
71 #include <mono/utils/mono-proclib.h>
72 #include <mono/utils/mono-state.h>
73 #include <mono/utils/mono-time.h>
74 #include <mono/metadata/w32handle.h>
75 #include <mono/metadata/threadpool.h>
77 #ifdef ENABLE_PERFTRACING
78 #include <mono/eventpipe/ep.h>
79 #include <mono/eventpipe/ds-server.h>
80 #endif
82 #include "mini.h"
83 #include "seq-points.h"
84 #include "tasklets.h"
85 #include <string.h>
86 #include <ctype.h>
87 #include "trace.h"
88 #include "version.h"
89 #include "aot-compiler.h"
90 #include "aot-runtime.h"
91 #include "llvmonly-runtime.h"
93 #include "jit-icalls.h"
95 #include "mini-gc.h"
96 #include "mini-llvm.h"
97 #include "debugger-agent.h"
98 #include "lldb.h"
99 #include "mini-runtime.h"
100 #include "interp/interp.h"
102 #ifdef MONO_ARCH_LLVM_SUPPORTED
103 #ifdef ENABLE_LLVM
104 #include "mini-llvm-cpp.h"
105 #include "llvm-jit.h"
106 #endif
107 #endif
108 #include "mono/metadata/icall-signatures.h"
109 #include "mono/utils/mono-tls-inline.h"
111 static guint32 default_opt = 0;
112 static gboolean default_opt_set = FALSE;
113 MonoMethodDesc *mono_stats_method_desc;
115 gboolean mono_compile_aot = FALSE;
116 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
117 gboolean mono_aot_only = FALSE;
118 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
119 gboolean mono_llvm_only = FALSE;
120 /* By default, don't require AOT but attempt to probe */
121 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NORMAL;
122 MonoEEFeatures mono_ee_features;
124 const char *mono_build_date;
125 gboolean mono_do_signal_chaining;
126 gboolean mono_do_crash_chaining;
127 int mini_verbose = 0;
130 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
131 * it can load AOT code compiled by LLVM.
133 gboolean mono_use_llvm = FALSE;
135 gboolean mono_use_fast_math = FALSE;
137 // Lists of allowlisted and blocklisted CPU features
138 MonoCPUFeatures mono_cpu_features_enabled = (MonoCPUFeatures)0;
140 #ifdef DISABLE_SIMD
141 MonoCPUFeatures mono_cpu_features_disabled = MONO_CPU_X86_FULL_SSEAVX_COMBINED;
142 #else
143 MonoCPUFeatures mono_cpu_features_disabled = (MonoCPUFeatures)0;
144 #endif
146 gboolean mono_use_interpreter = FALSE;
147 const char *mono_interp_opts_string = NULL;
149 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
150 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
151 static mono_mutex_t jit_mutex;
153 static MonoCodeManager *global_codeman;
155 MonoDebugOptions mini_debug_options;
156 char *sdb_options;
158 #ifdef VALGRIND_JIT_REGISTER_MAP
159 int valgrind_register;
160 #endif
161 GList* mono_aot_paths;
163 static GPtrArray *profile_options;
165 static GSList *tramp_infos;
166 GSList *mono_interp_only_classes;
168 static void register_icalls (void);
169 static void runtime_cleanup (MonoDomain *domain, gpointer user_data);
171 gboolean
172 mono_running_on_valgrind (void)
174 #ifndef HOST_WIN32
175 if (RUNNING_ON_VALGRIND){
176 #ifdef VALGRIND_JIT_REGISTER_MAP
177 valgrind_register = TRUE;
178 #endif
179 return TRUE;
180 } else
181 #endif
182 return FALSE;
185 void
186 mono_set_use_llvm (mono_bool use_llvm)
188 mono_use_llvm = (gboolean)use_llvm;
192 typedef struct {
193 void *ip;
194 MonoMethod *method;
195 } FindTrampUserData;
197 static void
198 find_tramp (gpointer key, gpointer value, gpointer user_data)
200 FindTrampUserData *ud = (FindTrampUserData*)user_data;
202 if (value == ud->ip)
203 ud->method = (MonoMethod*)key;
206 /* debug function */
207 char*
208 mono_get_method_from_ip (void *ip)
210 MonoJitInfo *ji;
211 MonoMethod *method;
212 char *method_name;
213 char *res;
214 MonoDomain *domain = mono_domain_get ();
215 MonoDebugSourceLocation *location;
216 FindTrampUserData user_data;
218 if (!domain)
219 domain = mono_get_root_domain ();
221 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
222 if (!ji) {
223 user_data.ip = ip;
224 user_data.method = NULL;
225 mono_domain_lock (domain);
226 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
227 mono_domain_unlock (domain);
228 if (user_data.method) {
229 char *mname = mono_method_full_name (user_data.method, TRUE);
230 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
231 g_free (mname);
232 return res;
234 else
235 return NULL;
236 } else if (ji->is_trampoline) {
237 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
238 return res;
241 method = jinfo_get_method (ji);
242 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
243 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
245 char *file_loc = NULL;
246 if (location)
247 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
249 const char *in_interp = ji->is_interp ? " interp" : "";
251 res = g_strdup_printf (" %s [{%p} + 0x%x%s] %s (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), in_interp, file_loc ? file_loc : "", ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
253 mono_debug_free_source_location (location);
254 g_free (method_name);
255 g_free (file_loc);
257 return res;
261 * mono_pmip:
262 * \param ip an instruction pointer address
264 * This method is used from a debugger to get the name of the
265 * method at address \p ip. This routine is typically invoked from
266 * a debugger like this:
268 * (gdb) print mono_pmip ($pc)
270 * \returns the name of the method at address \p ip.
272 G_GNUC_UNUSED char *
273 mono_pmip (void *ip)
275 return mono_get_method_from_ip (ip);
279 * mono_print_method_from_ip:
280 * \param ip an instruction pointer address
282 * This method is used from a debugger to get the name of the
283 * method at address \p ip.
285 * This prints the name of the method at address \p ip in the standard
286 * output. Unlike \c mono_pmip which returns a string, this routine
287 * prints the value on the standard output.
289 MONO_ATTR_USED void
290 mono_print_method_from_ip (void *ip)
292 MonoJitInfo *ji;
293 char *method;
294 MonoDebugSourceLocation *source;
295 MonoDomain *domain = mono_domain_get ();
296 MonoDomain *target_domain = mono_domain_get ();
297 FindTrampUserData user_data;
298 MonoGenericSharingContext*gsctx;
299 const char *shared_type;
301 if (!domain)
302 domain = mono_get_root_domain ();
303 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
304 if (ji && ji->is_trampoline) {
305 MonoTrampInfo *tinfo = ji->d.tramp_info;
307 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
308 return;
311 if (!ji) {
312 user_data.ip = ip;
313 user_data.method = NULL;
314 mono_domain_lock (domain);
315 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
316 mono_domain_unlock (domain);
318 if (user_data.method) {
319 char *mname = mono_method_full_name (user_data.method, TRUE);
320 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
321 g_free (mname);
322 return;
325 g_print ("No method at %p\n", ip);
326 fflush (stdout);
327 return;
329 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
330 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
332 gsctx = mono_jit_info_get_generic_sharing_context (ji);
333 shared_type = "";
334 if (gsctx) {
335 if (gsctx->is_gsharedvt)
336 shared_type = "gsharedvt ";
337 else
338 shared_type = "gshared ";
341 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);
343 if (source)
344 g_print ("%s:%d\n", source->source_file, source->row);
345 fflush (stdout);
347 mono_debug_free_source_location (source);
348 g_free (method);
352 * mono_method_same_domain:
354 * Determine whenever two compiled methods are in the same domain, thus
355 * the address of the callee can be embedded in the caller.
357 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
359 MonoMethod *cmethod;
361 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
362 return FALSE;
365 * If the call was made from domain-neutral to domain-specific
366 * code, we can't patch the call site.
368 if (caller->domain_neutral && !callee->domain_neutral)
369 return FALSE;
371 cmethod = jinfo_get_method (caller);
372 if ((cmethod->klass == mono_defaults.appdomain_class) &&
373 (strstr (cmethod->name, "InvokeInDomain"))) {
374 /* The InvokeInDomain methods change the current appdomain */
375 return FALSE;
378 return TRUE;
382 * mono_global_codeman_reserve:
384 * Allocate code memory from the global code manager.
386 void *(mono_global_codeman_reserve) (int size)
388 void *ptr;
390 if (mono_aot_only)
391 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
393 if (!global_codeman) {
394 /* This can happen during startup */
395 global_codeman = mono_code_manager_new ();
396 return mono_code_manager_reserve (global_codeman, size);
398 else {
399 mono_jit_lock ();
400 ptr = mono_code_manager_reserve (global_codeman, size);
401 mono_jit_unlock ();
402 return ptr;
406 /* The callback shouldn't take any locks */
407 void
408 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
410 mono_jit_lock ();
411 mono_code_manager_foreach (global_codeman, func, user_data);
412 mono_jit_unlock ();
416 * mono_create_unwind_op:
418 * Create an unwind op with the given parameters.
420 MonoUnwindOp*
421 mono_create_unwind_op (int when, int tag, int reg, int val)
423 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
425 op->op = tag;
426 op->reg = reg;
427 op->val = val;
428 op->when = when;
430 return op;
433 MonoJumpInfoToken *
434 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
436 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
437 res->image = image;
438 res->token = token;
439 res->has_context = context != NULL;
440 if (context)
441 memcpy (&res->context, context, sizeof (MonoGenericContext));
443 return res;
446 MonoJumpInfoToken *
447 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
449 return mono_jump_info_token_new2 (mp, image, token, NULL);
453 * mono_tramp_info_create:
455 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
456 * of JI, and UNWIND_OPS.
458 MonoTrampInfo*
459 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
461 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
463 info->name = g_strdup (name);
464 info->code = code;
465 info->code_size = code_size;
466 info->ji = ji;
467 info->unwind_ops = unwind_ops;
469 return info;
472 void
473 mono_tramp_info_free (MonoTrampInfo *info)
475 g_free (info->name);
477 // FIXME: ji
478 mono_free_unwind_info (info->unwind_ops);
479 if (info->owns_uw_info)
480 g_free (info->uw_info);
481 g_free (info);
484 static void
485 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
487 MonoJitInfo *ji;
489 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
490 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
491 ji->d.tramp_info = info;
492 ji->is_trampoline = TRUE;
494 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
496 mono_jit_info_table_add (domain, ji);
500 * mono_tramp_info_register:
502 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
503 * INFO can be NULL.
504 * Frees INFO.
506 static void
507 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
509 MonoTrampInfo *copy;
511 if (!info)
512 return;
514 if (!domain)
515 domain = mono_get_root_domain ();
517 if (domain)
518 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
519 else
520 copy = g_new0 (MonoTrampInfo, 1);
522 copy->code = info->code;
523 copy->code_size = info->code_size;
524 copy->name = g_strdup (info->name);
525 copy->method = info->method;
527 if (info->unwind_ops) {
528 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
529 copy->owns_uw_info = TRUE;
530 if (domain) {
531 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
532 guint8 *temp = copy->uw_info;
533 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
534 memcpy (copy->uw_info, temp, copy->uw_info_len);
535 g_free (temp);
537 } else {
538 /* Trampolines from aot have the unwind ops already encoded */
539 copy->uw_info = info->uw_info;
540 copy->uw_info_len = info->uw_info_len;
543 mono_save_trampoline_xdebug_info (info);
544 mono_lldb_save_trampoline_info (info);
546 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
547 if (!aot)
548 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
549 #endif
551 if (!domain) {
552 /* If no root domain has been created yet, postpone the registration. */
553 mono_jit_lock ();
554 tramp_infos = g_slist_prepend (tramp_infos, copy);
555 mono_jit_unlock ();
556 } else if (copy->uw_info || info->method) {
557 /* Only register trampolines that have unwind info */
558 register_trampoline_jit_info (domain, copy);
561 if (mono_jit_map_is_enabled ())
562 mono_emit_jit_tramp (info->code, info->code_size, info->name);
564 mono_tramp_info_free (info);
567 void
568 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
570 mono_tramp_info_register_internal (info, domain, FALSE);
573 void
574 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
576 mono_tramp_info_register_internal (info, domain, TRUE);
579 static void
580 mono_tramp_info_cleanup (void)
582 GSList *l;
584 for (l = tramp_infos; l; l = l->next) {
585 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
587 mono_tramp_info_free (info);
589 g_slist_free (tramp_infos);
592 /* Register trampolines created before the root domain was created in the jit info tables */
593 static void
594 register_trampolines (MonoDomain *domain)
596 GSList *l;
598 for (l = tramp_infos; l; l = l->next) {
599 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
601 register_trampoline_jit_info (domain, info);
605 G_GNUC_UNUSED static void
606 break_count (void)
611 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
612 * Set a breakpoint in break_count () to break the last time <x> is done.
614 G_GNUC_UNUSED gboolean
615 mono_debug_count (void)
617 static int count = 0, int_val = 0;
618 static gboolean inited, has_value = FALSE;
620 count ++;
622 if (!inited) {
623 char *value = g_getenv ("COUNT");
624 if (value) {
625 int_val = atoi (value);
626 g_free (value);
627 has_value = TRUE;
629 inited = TRUE;
632 if (!has_value)
633 return TRUE;
635 if (count == int_val)
636 break_count ();
638 if (count > int_val)
639 return FALSE;
641 return TRUE;
644 MonoMethod*
645 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
647 /* This icall is used to check for exceptions, so don't check in the wrapper */
648 gboolean check_exc = (callinfo != &mono_get_jit_icall_info ()->mono_thread_interruption_checkpoint);
650 return mono_marshal_get_icall_wrapper (callinfo, check_exc);
653 gconstpointer
654 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
656 ERROR_DECL (error);
657 MonoMethod *wrapper;
658 gconstpointer addr, trampoline;
659 MonoDomain *domain = mono_get_root_domain ();
661 if (callinfo->wrapper)
662 return callinfo->wrapper;
664 wrapper = mono_icall_get_wrapper_method (callinfo);
666 if (do_compile) {
667 addr = mono_compile_method_checked (wrapper, error);
668 mono_error_assert_ok (error);
669 mono_memory_barrier ();
670 callinfo->wrapper = addr;
671 return addr;
672 } else {
673 if (callinfo->trampoline)
674 return callinfo->trampoline;
675 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
676 mono_error_assert_ok (error);
677 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
679 mono_loader_lock ();
680 if (!callinfo->trampoline) {
681 callinfo->trampoline = trampoline;
683 mono_loader_unlock ();
685 return callinfo->trampoline;
689 gconstpointer
690 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
692 return mono_icall_get_wrapper_full (callinfo, FALSE);
695 static MonoJitDynamicMethodInfo*
696 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
698 MonoJitDynamicMethodInfo *res;
700 if (domain_jit_info (domain)->dynamic_code_hash)
701 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
702 else
703 res = NULL;
704 return res;
707 #ifdef __cplusplus
708 template <typename T>
709 static void
710 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, T func, const char *symbol, gboolean no_wrapper)
711 #else
712 static void
713 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, gpointer func, const char *symbol, gboolean no_wrapper)
714 #endif
716 #ifndef DISABLE_JIT
717 mini_register_opcode_emulation (opcode, jit_icall_info, name, sig, func, symbol, no_wrapper);
718 #else
719 // FIXME ifdef in mini_register_opcode_emulation and just call it.
721 g_assert (!sig->hasthis);
722 g_assert (sig->param_count < 3);
724 mono_register_jit_icall_info (jit_icall_info, func, name, sig, no_wrapper, symbol);
725 #endif
728 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
729 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
732 * For JIT icalls implemented in C.
733 * NAME should be the same as the name of the C function whose address is FUNC.
734 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
735 * can't throw exceptions.
737 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
738 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
740 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
741 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
742 * must be extern "C".
744 #define register_icall(func, sig, avoid_wrapper) \
745 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
747 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
748 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
751 * Register an icall where FUNC is dynamically generated or otherwise not
752 * possible to link to it using NAME during AOT.
754 * func is an expression, such a local variable or a function call to get a function pointer.
755 * name is an identifier
757 * Providing func and name separately is what distinguishes "dyn" from regular.
759 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
761 #define register_dyn_icall(func, name, sig, save) \
762 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
764 MonoLMF *
765 mono_get_lmf (void)
767 MonoJitTlsData *jit_tls;
769 if ((jit_tls = mono_tls_get_jit_tls ()))
770 return jit_tls->lmf;
772 * We do not assert here because this function can be called from
773 * mini-gc.c on a thread that has not executed any managed code, yet
774 * (the thread object allocation can trigger a collection).
776 return NULL;
779 void
780 mono_set_lmf (MonoLMF *lmf)
782 (*mono_get_lmf_addr ()) = lmf;
785 static void
786 mono_set_jit_tls (MonoJitTlsData *jit_tls)
788 MonoThreadInfo *info;
790 mono_tls_set_jit_tls (jit_tls);
792 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
793 info = mono_thread_info_current ();
794 if (info)
795 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
798 static void
799 mono_set_lmf_addr (MonoLMF **lmf_addr)
801 MonoThreadInfo *info;
803 mono_tls_set_lmf_addr (lmf_addr);
805 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
806 info = mono_thread_info_current ();
807 if (info)
808 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
812 * mono_push_lmf:
814 * Push an MonoLMFExt frame on the LMF stack.
816 void
817 mono_push_lmf (MonoLMFExt *ext)
819 MonoLMF **lmf_addr;
821 lmf_addr = mono_get_lmf_addr ();
823 ext->lmf.previous_lmf = *lmf_addr;
824 /* Mark that this is a MonoLMFExt */
825 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
827 mono_set_lmf ((MonoLMF*)ext);
831 * mono_pop_lmf:
833 * Pop the last frame from the LMF stack.
835 void
836 mono_pop_lmf (MonoLMF *lmf)
838 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
842 * mono_jit_thread_attach:
844 * Called by Xamarin.Mac and other products. Attach thread to runtime if
845 * needed and switch to @domain.
847 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
849 * If the thread is newly-attached, put into GC Safe mode.
851 * @return the original domain which needs to be restored, or NULL.
853 MonoDomain*
854 mono_jit_thread_attach (MonoDomain *domain)
856 MonoDomain *orig;
857 gboolean attached;
859 if (!domain) {
860 /* Happens when called from AOTed code which is only used in the root domain. */
861 domain = mono_get_root_domain ();
864 g_assert (domain);
866 attached = mono_tls_get_jit_tls () != NULL;
868 if (!attached) {
869 // #678164
870 gboolean background = TRUE;
871 mono_thread_attach_external_native_thread (domain, background);
873 /* mono_jit_thread_attach is external-only and not called by
874 * the runtime on any of our own threads. So if we get here,
875 * the thread is running native code - leave it in GC Safe mode
876 * and leave it to the n2m invoke wrappers or MONO_API entry
877 * points to switch to GC Unsafe.
879 MONO_STACKDATA (stackdata);
880 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
883 orig = mono_domain_get ();
884 if (orig != domain)
885 mono_domain_set_fast (domain, TRUE);
887 return orig != domain ? orig : NULL;
891 * mono_jit_set_domain:
893 * Set domain to @domain if @domain is not null
895 void
896 mono_jit_set_domain (MonoDomain *domain)
898 g_assert (!mono_threads_is_blocking_transition_enabled ());
900 if (domain)
901 mono_domain_set_fast (domain, TRUE);
905 * mono_thread_abort:
906 * \param obj exception object
907 * Abort the thread, print exception information and stack trace
909 static void
910 mono_thread_abort (MonoObject *obj)
912 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
914 /* handle_remove should be eventually called for this thread, too
915 g_free (jit_tls);*/
917 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
918 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
919 ((obj->vtable->klass) == mono_class_try_get_appdomain_unloaded_exception_class () &&
920 mono_thread_info_current ()->runtime_thread)) {
921 mono_thread_exit ();
922 } else {
923 mono_invoke_unhandled_exception_hook (obj);
927 static MonoJitTlsData*
928 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
930 MonoJitTlsData *jit_tls;
931 MonoLMF *lmf;
933 jit_tls = mono_tls_get_jit_tls ();
934 if (jit_tls)
935 return jit_tls;
937 jit_tls = g_new0 (MonoJitTlsData, 1);
939 jit_tls->abort_func = abort_func;
940 jit_tls->end_of_stack = stack_start;
942 mono_set_jit_tls (jit_tls);
944 lmf = g_new0 (MonoLMF, 1);
945 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
947 jit_tls->first_lmf = lmf;
949 mono_set_lmf_addr (&jit_tls->lmf);
951 jit_tls->lmf = lmf;
953 #ifdef MONO_ARCH_HAVE_TLS_INIT
954 mono_arch_tls_init ();
955 #endif
957 mono_setup_altstack (jit_tls);
959 return jit_tls;
962 static void
963 free_jit_tls_data (MonoJitTlsData *jit_tls)
965 //This happens during AOT cuz the thread is never attached
966 if (!jit_tls)
967 return;
968 mono_free_altstack (jit_tls);
970 if (jit_tls->interp_context)
971 mini_get_interp_callbacks ()->free_context (jit_tls->interp_context);
973 g_free (jit_tls->first_lmf);
974 g_free (jit_tls);
977 static void
978 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
980 MonoThreadInfo *thread;
981 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
982 thread = mono_thread_info_current_unchecked ();
983 if (thread)
984 thread->jit_data = jit_tls;
986 mono_arch_cpu_init ();
989 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
991 static void
992 mono_thread_abort_dummy (MonoObject *obj)
994 if (mono_thread_attach_aborted_cb)
995 mono_thread_attach_aborted_cb (obj);
996 else
997 mono_thread_abort (obj);
1000 static void
1001 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
1003 MonoThreadInfo *thread;
1004 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
1005 thread = mono_thread_info_current_unchecked ();
1006 if (thread)
1007 thread->jit_data = jit_tls;
1009 mono_arch_cpu_init ();
1012 static void
1013 mini_thread_cleanup (MonoNativeThreadId tid)
1015 MonoJitTlsData *jit_tls = NULL;
1016 MonoThreadInfo *info;
1018 info = mono_thread_info_current_unchecked ();
1020 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1021 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1022 * not a trivial thing.
1024 * The current offender is mono_thread_manage which cleanup threads from the outside.
1026 if (info && mono_thread_info_get_tid (info) == tid) {
1027 jit_tls = info->jit_data;
1028 info->jit_data = NULL;
1030 mono_set_jit_tls (NULL);
1032 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1033 if (mono_get_lmf ()) {
1034 mono_set_lmf (NULL);
1035 mono_set_lmf_addr (NULL);
1037 } else {
1038 info = mono_thread_info_lookup (tid);
1039 if (info) {
1040 jit_tls = info->jit_data;
1041 info->jit_data = NULL;
1043 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1046 if (jit_tls)
1047 free_jit_tls_data (jit_tls);
1050 MonoJumpInfo *
1051 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1053 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1055 ji->ip.i = ip;
1056 ji->type = type;
1057 ji->data.target = target;
1058 ji->next = list;
1060 return ji;
1063 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1065 static const char* const patch_info_str[] = {
1066 #define PATCH_INFO(a,b) "" #a,
1067 #include "patch-info.h"
1068 #undef PATCH_INFO
1071 const char*
1072 mono_ji_type_to_string (MonoJumpInfoType type)
1074 return patch_info_str [type];
1077 void
1078 mono_print_ji (const MonoJumpInfo *ji)
1080 const char *type = patch_info_str [ji->type];
1081 switch (ji->type) {
1082 case MONO_PATCH_INFO_RGCTX_FETCH:
1083 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1084 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1086 printf ("[%s ", type);
1087 mono_print_ji (entry->data);
1088 printf (" -> %s]", mono_rgctx_info_type_to_str (entry->info_type));
1089 break;
1091 case MONO_PATCH_INFO_METHOD:
1092 case MONO_PATCH_INFO_METHODCONST:
1093 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1094 char *s = mono_method_get_full_name (ji->data.method);
1095 printf ("[%s %s]", type, s);
1096 g_free (s);
1097 break;
1099 case MONO_PATCH_INFO_JIT_ICALL_ID:
1100 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji->data.jit_icall_id)->name);
1101 break;
1102 case MONO_PATCH_INFO_CLASS:
1103 case MONO_PATCH_INFO_VTABLE: {
1104 char *name = mono_class_full_name (ji->data.klass);
1105 printf ("[%s %s]", type, name);
1106 g_free (name);
1107 break;
1109 default:
1110 printf ("[%s]", type);
1111 break;
1115 #else
1117 const char*
1118 mono_ji_type_to_string (MonoJumpInfoType type)
1120 return "";
1123 void
1124 mono_print_ji (const MonoJumpInfo *ji)
1128 #endif
1131 * mono_patch_info_dup_mp:
1133 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1135 MonoJumpInfo*
1136 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1138 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1139 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1141 switch (patch_info->type) {
1142 case MONO_PATCH_INFO_RVA:
1143 case MONO_PATCH_INFO_LDSTR:
1144 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1145 case MONO_PATCH_INFO_LDTOKEN:
1146 case MONO_PATCH_INFO_DECLSEC:
1147 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1148 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1149 break;
1150 case MONO_PATCH_INFO_SWITCH:
1151 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1152 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1153 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1154 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1155 break;
1156 case MONO_PATCH_INFO_RGCTX_FETCH:
1157 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1158 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1159 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1160 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1161 break;
1162 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1163 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1164 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1165 break;
1166 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1167 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1168 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1169 break;
1170 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1171 MonoGSharedVtMethodInfo *info;
1172 MonoGSharedVtMethodInfo *oinfo;
1173 int i;
1175 oinfo = patch_info->data.gsharedvt_method;
1176 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1177 res->data.gsharedvt_method = info;
1178 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1179 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1180 for (i = 0; i < oinfo->num_entries; ++i) {
1181 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1182 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1184 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1186 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1187 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1188 break;
1190 case MONO_PATCH_INFO_VIRT_METHOD: {
1191 MonoJumpInfoVirtMethod *info;
1192 MonoJumpInfoVirtMethod *oinfo;
1194 oinfo = patch_info->data.virt_method;
1195 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1196 res->data.virt_method = info;
1197 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1198 break;
1200 default:
1201 break;
1204 return res;
1207 guint
1208 mono_patch_info_hash (gconstpointer data)
1210 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1211 const MonoJumpInfoType type = ji->type;
1212 guint hash = type << 8;
1214 switch (type) {
1215 case MONO_PATCH_INFO_RVA:
1216 case MONO_PATCH_INFO_LDSTR:
1217 case MONO_PATCH_INFO_LDTOKEN:
1218 case MONO_PATCH_INFO_DECLSEC:
1219 return hash | ji->data.token->token;
1220 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1221 return hash | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1222 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: // Hash on the selector name
1223 case MONO_PATCH_INFO_LDSTR_LIT:
1224 return g_str_hash (ji->data.name);
1225 case MONO_PATCH_INFO_VTABLE:
1226 case MONO_PATCH_INFO_CLASS:
1227 case MONO_PATCH_INFO_IID:
1228 case MONO_PATCH_INFO_ADJUSTED_IID:
1229 case MONO_PATCH_INFO_METHODCONST:
1230 case MONO_PATCH_INFO_METHOD:
1231 case MONO_PATCH_INFO_METHOD_JUMP:
1232 case MONO_PATCH_INFO_METHOD_FTNDESC:
1233 case MONO_PATCH_INFO_IMAGE:
1234 case MONO_PATCH_INFO_ICALL_ADDR:
1235 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1236 case MONO_PATCH_INFO_FIELD:
1237 case MONO_PATCH_INFO_SFLDA:
1238 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1239 case MONO_PATCH_INFO_METHOD_RGCTX:
1240 case MONO_PATCH_INFO_SIGNATURE:
1241 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1242 case MONO_PATCH_INFO_AOT_JIT_INFO:
1243 case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE:
1244 return hash | (gssize)ji->data.target;
1245 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1246 return hash | (gssize)ji->data.gsharedvt->method;
1247 case MONO_PATCH_INFO_RGCTX_FETCH:
1248 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1249 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1250 hash |= e->in_mrgctx | e->info_type | mono_patch_info_hash (e->data);
1251 if (e->in_mrgctx)
1252 return hash | (gssize)e->d.method;
1253 else
1254 return hash | (gssize)e->d.klass;
1256 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1257 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1258 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1259 case MONO_PATCH_INFO_GC_NURSERY_START:
1260 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1261 case MONO_PATCH_INFO_GOT_OFFSET:
1262 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1263 case MONO_PATCH_INFO_AOT_MODULE:
1264 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1265 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1266 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES:
1267 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE:
1268 return hash;
1269 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1270 return hash | ji->data.uindex;
1271 case MONO_PATCH_INFO_JIT_ICALL_ID:
1272 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1273 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1274 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1275 return hash | ji->data.index;
1276 case MONO_PATCH_INFO_SWITCH:
1277 return hash | ji->data.table->table_size;
1278 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1279 return hash | (gssize)ji->data.gsharedvt_method->method;
1280 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1281 return hash | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1282 case MONO_PATCH_INFO_VIRT_METHOD: {
1283 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1285 return hash | (gssize)info->klass | (gssize)info->method;
1287 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1288 return hash | mono_signature_hash (ji->data.sig);
1289 case MONO_PATCH_INFO_R8_GOT:
1290 return hash | (guint32)*(double*)ji->data.target;
1291 case MONO_PATCH_INFO_R4_GOT:
1292 return hash | (guint32)*(float*)ji->data.target;
1293 default:
1294 printf ("info type: %d\n", ji->type);
1295 mono_print_ji (ji); printf ("\n");
1296 g_assert_not_reached ();
1297 case MONO_PATCH_INFO_NONE:
1298 return 0;
1303 * mono_patch_info_equal:
1305 * This might fail to recognize equivalent patches, i.e. floats, so its only
1306 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1307 * in AOT.
1309 gint
1310 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1312 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1313 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1315 MonoJumpInfoType const ji1_type = ji1->type;
1316 MonoJumpInfoType const ji2_type = ji2->type;
1318 if (ji1_type != ji2_type)
1319 return 0;
1321 switch (ji1_type) {
1322 case MONO_PATCH_INFO_RVA:
1323 case MONO_PATCH_INFO_LDSTR:
1324 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1325 case MONO_PATCH_INFO_LDTOKEN:
1326 case MONO_PATCH_INFO_DECLSEC:
1327 return ji1->data.token->image == ji2->data.token->image &&
1328 ji1->data.token->token == ji2->data.token->token &&
1329 ji1->data.token->has_context == ji2->data.token->has_context &&
1330 ji1->data.token->context.class_inst == ji2->data.token->context.class_inst &&
1331 ji1->data.token->context.method_inst == ji2->data.token->context.method_inst;
1332 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1333 case MONO_PATCH_INFO_LDSTR_LIT:
1334 return g_str_equal (ji1->data.name, ji2->data.name);
1335 case MONO_PATCH_INFO_RGCTX_FETCH:
1336 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1337 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1338 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1340 return e1->d.method == e2->d.method && e1->d.klass == e2->d.klass && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
1342 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1343 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1344 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1346 return c1->sig == c2->sig && c1->method == c2->method;
1348 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1349 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1350 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1351 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;
1352 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1353 return ji1->data.uindex == ji2->data.uindex;
1354 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1355 return ji1->data.index == ji2->data.index;
1356 case MONO_PATCH_INFO_JIT_ICALL_ID:
1357 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1358 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1359 return ji1->data.jit_icall_id == ji2->data.jit_icall_id;
1360 case MONO_PATCH_INFO_VIRT_METHOD:
1361 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1362 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1363 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig);
1364 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1365 case MONO_PATCH_INFO_NONE:
1366 return 1;
1367 default:
1368 break;
1371 return ji1->data.target == ji2->data.target;
1374 gpointer
1375 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1377 unsigned char *ip = patch_info->ip.i + code;
1378 gconstpointer target = NULL;
1380 error_init (error);
1382 switch (patch_info->type) {
1383 case MONO_PATCH_INFO_BB:
1385 * FIXME: This could be hit for methods without a prolog. Should use -1
1386 * but too much code depends on a 0 initial value.
1388 //g_assert (patch_info->data.bb->native_offset);
1389 target = patch_info->data.bb->native_offset + code;
1390 break;
1391 case MONO_PATCH_INFO_ABS:
1392 target = patch_info->data.target;
1393 break;
1394 case MONO_PATCH_INFO_LABEL:
1395 target = patch_info->data.inst->inst_c0 + code;
1396 break;
1397 case MONO_PATCH_INFO_IP:
1398 target = ip;
1399 break;
1400 case MONO_PATCH_INFO_JIT_ICALL_ID: {
1401 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1402 target = mono_icall_get_wrapper (mi);
1403 break;
1405 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1406 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1407 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1408 target = mi->func;
1409 break;
1411 case MONO_PATCH_INFO_METHOD_JUMP:
1412 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1413 if (!is_ok (error))
1414 return NULL;
1415 break;
1416 case MONO_PATCH_INFO_METHOD:
1417 if (patch_info->data.method == method) {
1418 target = code;
1419 } else {
1420 /* get the trampoline to the method from the domain */
1421 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1422 if (!is_ok (error))
1423 return NULL;
1425 break;
1426 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1428 * Return an ftndesc for either AOTed code, or for an interp entry.
1430 target = mini_llvmonly_load_method_ftndesc (patch_info->data.method, FALSE, FALSE, error);
1431 return_val_if_nok (error, NULL);
1432 break;
1434 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1435 gpointer code_slot;
1437 mono_domain_lock (domain);
1438 if (!domain_jit_info (domain)->method_code_hash)
1439 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1440 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1441 if (!code_slot) {
1442 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1443 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1445 mono_domain_unlock (domain);
1446 target = code_slot;
1447 break;
1449 case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE: {
1450 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1451 break;
1453 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1454 target = (gpointer)&mono_polling_required;
1455 break;
1456 case MONO_PATCH_INFO_SWITCH: {
1457 gpointer *jump_table;
1458 int i;
1459 if (method && method->dynamic) {
1460 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1461 } else {
1462 MonoMemoryManager *mem_manager = m_method_get_mem_manager (domain, method);
1463 if (mono_aot_only) {
1464 jump_table = (void **)mono_mem_manager_alloc (mem_manager, sizeof (gpointer) * patch_info->data.table->table_size);
1465 } else {
1466 jump_table = (void **)mono_mem_manager_code_reserve (mem_manager, sizeof (gpointer) * patch_info->data.table->table_size);
1470 mono_codeman_enable_write ();
1471 for (i = 0; i < patch_info->data.table->table_size; i++) {
1472 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1474 mono_codeman_disable_write ();
1476 target = jump_table;
1477 break;
1479 case MONO_PATCH_INFO_METHODCONST:
1480 case MONO_PATCH_INFO_CLASS:
1481 case MONO_PATCH_INFO_IMAGE:
1482 case MONO_PATCH_INFO_FIELD:
1483 case MONO_PATCH_INFO_SIGNATURE:
1484 case MONO_PATCH_INFO_AOT_MODULE:
1485 target = patch_info->data.target;
1486 break;
1487 case MONO_PATCH_INFO_IID:
1488 mono_class_init_internal (patch_info->data.klass);
1489 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1490 break;
1491 case MONO_PATCH_INFO_ADJUSTED_IID:
1492 mono_class_init_internal (patch_info->data.klass);
1493 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1494 break;
1495 case MONO_PATCH_INFO_VTABLE:
1496 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1497 mono_error_assert_ok (error);
1498 break;
1499 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1500 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1502 if (del_tramp->is_virtual)
1503 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1504 else
1505 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1506 break;
1508 case MONO_PATCH_INFO_SFLDA: {
1509 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1510 mono_error_assert_ok (error);
1512 if (mono_class_field_is_special_static (patch_info->data.field)) {
1513 gpointer addr = NULL;
1515 mono_domain_lock (domain);
1516 if (domain->special_static_fields)
1517 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1518 mono_domain_unlock (domain);
1519 g_assert (addr);
1520 return addr;
1523 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (!method || mono_class_needs_cctor_run (vtable->klass, method)))
1524 /* Done by the generated code */
1526 else {
1527 if (run_cctors) {
1528 if (!mono_runtime_class_init_full (vtable, error)) {
1529 return NULL;
1533 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1534 break;
1536 case MONO_PATCH_INFO_RVA: {
1537 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1538 guint32 rva;
1540 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1541 target = mono_image_rva_map (patch_info->data.token->image, rva);
1542 break;
1544 case MONO_PATCH_INFO_R4:
1545 case MONO_PATCH_INFO_R4_GOT:
1546 case MONO_PATCH_INFO_R8:
1547 case MONO_PATCH_INFO_R8_GOT:
1548 target = patch_info->data.target;
1549 break;
1550 case MONO_PATCH_INFO_EXC_NAME:
1551 target = patch_info->data.name;
1552 break;
1553 case MONO_PATCH_INFO_LDSTR:
1554 target =
1555 mono_ldstr_checked (domain, patch_info->data.token->image,
1556 mono_metadata_token_index (patch_info->data.token->token), error);
1557 break;
1558 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1559 gpointer handle;
1560 MonoClass *handle_class;
1562 handle = mono_ldtoken_checked (patch_info->data.token->image,
1563 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1564 if (!is_ok (error))
1565 return NULL;
1566 mono_class_init_internal (handle_class);
1567 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType *)handle));
1569 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1570 if (!is_ok (error))
1571 return NULL;
1572 break;
1574 case MONO_PATCH_INFO_LDTOKEN: {
1575 gpointer handle;
1576 MonoClass *handle_class;
1578 handle = mono_ldtoken_checked (patch_info->data.token->image,
1579 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1580 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1581 mono_class_init_internal (handle_class);
1583 target = handle;
1584 break;
1586 case MONO_PATCH_INFO_DECLSEC:
1587 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1588 break;
1589 case MONO_PATCH_INFO_ICALL_ADDR:
1590 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1591 /* run_cctors == 0 -> AOT */
1592 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1593 if (run_cctors) {
1594 target = mono_lookup_pinvoke_call_internal (patch_info->data.method, error);
1595 if (!target) {
1596 if (mono_aot_only)
1597 return NULL;
1598 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));
1600 } else {
1601 target = NULL;
1603 } else {
1604 target = mono_lookup_internal_call (patch_info->data.method);
1606 if (mono_is_missing_icall_addr (target) && run_cctors)
1607 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1609 break;
1610 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1611 target = &mono_thread_interruption_request_flag;
1612 break;
1613 case MONO_PATCH_INFO_METHOD_RGCTX:
1614 target = mini_method_get_rgctx (patch_info->data.method);
1615 break;
1616 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1617 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1619 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1620 break;
1622 case MONO_PATCH_INFO_BB_OVF:
1623 case MONO_PATCH_INFO_EXC_OVF:
1624 case MONO_PATCH_INFO_GOT_OFFSET:
1625 case MONO_PATCH_INFO_NONE:
1626 break;
1627 case MONO_PATCH_INFO_RGCTX_FETCH: {
1628 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1630 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1631 break;
1633 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1634 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1635 if (!run_cctors)
1636 /* AOT, not needed */
1637 target = NULL;
1638 else
1639 target = mono_arch_get_seq_point_info (domain, code);
1640 break;
1641 #endif
1642 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1643 int card_table_shift_bits;
1644 gpointer card_table_mask;
1646 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1647 break;
1649 case MONO_PATCH_INFO_GC_NURSERY_START: {
1650 int shift_bits;
1651 size_t size;
1653 target = mono_gc_get_nursery (&shift_bits, &size);
1654 break;
1656 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1657 int shift_bits;
1658 size_t size;
1660 mono_gc_get_nursery (&shift_bits, &size);
1662 target = (gpointer)(gssize)shift_bits;
1663 break;
1665 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1666 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1667 break;
1669 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1670 target = NULL;
1671 break;
1673 case MONO_PATCH_INFO_LDSTR_LIT: {
1674 int len;
1675 char *s;
1677 len = strlen ((const char *)patch_info->data.target);
1678 s = (char *)mono_domain_alloc0 (domain, len + 1);
1679 memcpy (s, patch_info->data.target, len);
1680 target = s;
1682 break;
1684 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1685 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1686 break;
1687 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1688 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1689 break;
1691 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1692 target = (gpointer) &mono_profiler_state.exception_clause_count;
1693 break;
1695 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES:
1696 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE: {
1697 /* Resolved in aot-runtime.c */
1698 g_assert_not_reached ();
1699 target = NULL;
1700 break;
1702 default:
1703 g_assert_not_reached ();
1706 return (gpointer)target;
1710 * mini_register_jump_site:
1712 * Register IP as a jump/tailcall site which calls METHOD.
1713 * This is needed because common_call_trampoline () cannot patch
1714 * the call site because the caller ip is not available for jumps.
1716 void
1717 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1719 MonoJumpList *jlist;
1721 MonoMethod *shared_method = mini_method_to_shared (method);
1722 method = shared_method ? shared_method : method;
1724 mono_domain_lock (domain);
1725 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1726 if (!jlist) {
1727 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1728 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1730 jlist->list = g_slist_prepend (jlist->list, ip);
1731 mono_domain_unlock (domain);
1735 * mini_patch_jump_sites:
1737 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1739 void
1740 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1742 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1744 if (!hash)
1745 return;
1747 MonoJumpInfo patch_info;
1748 MonoJumpList *jlist;
1749 GSList *tmp;
1751 /* The caller/callee might use different instantiations */
1752 MonoMethod *shared_method = mini_method_to_shared (method);
1753 method = shared_method ? shared_method : method;
1755 mono_domain_lock (domain);
1756 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1757 if (jlist)
1758 g_hash_table_remove (hash, method);
1759 mono_domain_unlock (domain);
1760 if (jlist) {
1761 patch_info.next = NULL;
1762 patch_info.ip.i = 0;
1763 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1764 patch_info.data.method = method;
1766 mono_codeman_enable_write ();
1768 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1769 for (tmp = jlist->list; tmp; tmp = tmp->next)
1770 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1771 #else
1772 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1773 // for gshared methods
1774 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1775 ERROR_DECL (error);
1776 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1777 mono_error_assert_ok (error);
1779 #endif
1781 mono_codeman_disable_write ();
1786 * mini_patch_llvm_jit_callees:
1788 * Patch function address slots used by llvm JITed code.
1790 void
1791 mini_patch_llvm_jit_callees (MonoDomain *domain, MonoMethod *method, gpointer addr)
1793 if (!domain_jit_info (domain)->llvm_jit_callees)
1794 return;
1795 GSList *callees = (GSList*)g_hash_table_lookup (domain_jit_info (domain)->llvm_jit_callees, method);
1796 GSList *l;
1798 for (l = callees; l; l = l->next) {
1799 gpointer *slot = (gpointer*)l->data;
1801 *slot = addr;
1805 void
1806 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1808 MonoGenericInst *inst;
1809 int i;
1811 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1813 if (context && context->class_inst) {
1814 inst = context->class_inst;
1815 for (i = 0; i < inst->type_argc; ++i) {
1816 MonoType *type = inst->type_argv [i];
1818 if (mini_is_gsharedvt_gparam (type))
1819 gsctx->is_gsharedvt = TRUE;
1822 if (context && context->method_inst) {
1823 inst = context->method_inst;
1825 for (i = 0; i < inst->type_argc; ++i) {
1826 MonoType *type = inst->type_argv [i];
1828 if (mini_is_gsharedvt_gparam (type))
1829 gsctx->is_gsharedvt = TRUE;
1835 * LOCKING: Acquires the jit code hash lock.
1837 MonoJitInfo*
1838 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1840 MonoJitInfo *ji;
1841 static gboolean inited = FALSE;
1842 static int lookups = 0;
1843 static int failed_lookups = 0;
1845 mono_domain_jit_code_hash_lock (domain);
1846 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1847 if (!ji && shared) {
1848 /* Try generic sharing */
1849 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1850 if (ji && !ji->has_generic_jit_info)
1851 ji = NULL;
1852 if (!inited) {
1853 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1854 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1855 inited = TRUE;
1858 ++lookups;
1859 if (!ji)
1860 ++failed_lookups;
1862 mono_domain_jit_code_hash_unlock (domain);
1864 return ji;
1867 static MonoJitInfo*
1868 lookup_method (MonoDomain *domain, MonoMethod *method)
1870 ERROR_DECL (error);
1871 MonoJitInfo *ji;
1872 MonoMethod *shared;
1874 ji = mini_lookup_method (domain, method, NULL);
1876 if (!ji) {
1877 if (!mono_method_is_generic_sharable (method, FALSE))
1878 return NULL;
1879 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1880 mono_error_assert_ok (error);
1881 ji = mini_lookup_method (domain, method, shared);
1884 return ji;
1887 MonoClass*
1888 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1890 ERROR_DECL (error);
1891 MonoClass *klass;
1893 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1894 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1895 if (context) {
1896 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1897 mono_error_cleanup (error); /* FIXME don't swallow the error */
1899 } else {
1900 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1901 mono_error_cleanup (error); /* FIXME don't swallow the error */
1903 if (klass)
1904 mono_class_init_internal (klass);
1905 return klass;
1908 #if ENABLE_JIT_MAP
1909 static FILE* perf_map_file;
1911 void
1912 mono_enable_jit_map (void)
1914 if (!perf_map_file) {
1915 char name [64];
1916 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1917 unlink (name);
1918 perf_map_file = fopen (name, "w");
1922 void
1923 mono_emit_jit_tramp (void *start, int size, const char *desc)
1925 if (perf_map_file)
1926 fprintf (perf_map_file, "%" PRIx64 " %x %s\n", (guint64)(gsize)start, size, desc);
1929 void
1930 mono_emit_jit_map (MonoJitInfo *jinfo)
1932 if (perf_map_file) {
1933 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1934 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1935 g_free (name);
1939 gboolean
1940 mono_jit_map_is_enabled (void)
1942 return perf_map_file != NULL;
1945 #endif
1947 #ifdef ENABLE_JIT_DUMP
1948 #include <sys/mman.h>
1949 #include <sys/syscall.h>
1950 #include <elf.h>
1952 static FILE *perf_dump_file;
1953 static mono_mutex_t perf_dump_mutex;
1954 static void *perf_dump_mmap_addr = MAP_FAILED;
1955 static guint32 perf_dump_pid;
1956 static clockid_t clock_id = CLOCK_MONOTONIC;
1958 enum {
1959 JIT_DUMP_MAGIC = 0x4A695444,
1960 JIT_DUMP_VERSION = 2,
1961 #if HOST_X86
1962 ELF_MACHINE = EM_386,
1963 #elif HOST_AMD64
1964 ELF_MACHINE = EM_X86_64,
1965 #elif HOST_ARM
1966 ELF_MACHINE = EM_ARM,
1967 #elif HOST_ARM64
1968 ELF_MACHINE = EM_AARCH64,
1969 #elif HOST_POWERPC64
1970 ELF_MACHINE = EM_PPC64,
1971 #elif HOST_S390X
1972 ELF_MACHINE = EM_S390,
1973 #elif HOST_RISCV
1974 ELF_MACHINE = EM_RISCV,
1975 #elif HOST_MIPS
1976 ELF_MACHINE = EM_MIPS,
1977 #endif
1978 JIT_CODE_LOAD = 0
1980 typedef struct
1982 guint32 magic;
1983 guint32 version;
1984 guint32 total_size;
1985 guint32 elf_mach;
1986 guint32 pad1;
1987 guint32 pid;
1988 guint64 timestamp;
1989 guint64 flags;
1990 } FileHeader;
1991 typedef struct
1993 guint32 id;
1994 guint32 total_size;
1995 guint64 timestamp;
1996 } RecordHeader;
1997 typedef struct
1999 RecordHeader header;
2000 guint32 pid;
2001 guint32 tid;
2002 guint64 vma;
2003 guint64 code_addr;
2004 guint64 code_size;
2005 guint64 code_index;
2006 // Null terminated function name
2007 // Native code
2008 } JitCodeLoadRecord;
2010 static void add_file_header_info (FileHeader *header);
2011 static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record);
2013 void
2014 mono_enable_jit_dump (void)
2016 if (perf_dump_pid == 0)
2017 perf_dump_pid = getpid();
2019 if (!perf_dump_file) {
2020 char name [64];
2021 FileHeader header;
2022 memset (&header, 0, sizeof (header));
2024 mono_os_mutex_init (&perf_dump_mutex);
2025 mono_os_mutex_lock (&perf_dump_mutex);
2027 g_snprintf (name, sizeof (name), "/tmp/jit-%d.dump", perf_dump_pid);
2028 unlink (name);
2029 perf_dump_file = fopen (name, "w");
2031 add_file_header_info (&header);
2032 if (perf_dump_file) {
2033 fwrite (&header, sizeof (header), 1, perf_dump_file);
2034 //This informs perf of the presence of the jitdump file and support for the feature.
2035 perf_dump_mmap_addr = mmap (NULL, sizeof (header), PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno (perf_dump_file), 0);
2038 mono_os_mutex_unlock (&perf_dump_mutex);
2042 static void
2043 add_file_header_info (FileHeader *header)
2045 header->magic = JIT_DUMP_MAGIC;
2046 header->version = JIT_DUMP_VERSION;
2047 header->total_size = sizeof (header);
2048 header->elf_mach = ELF_MACHINE;
2049 header->pad1 = 0;
2050 header->pid = perf_dump_pid;
2051 header->timestamp = mono_clock_get_time_ns (clock_id);
2052 header->flags = 0;
2055 void
2056 mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2058 static uint64_t code_index;
2060 if (perf_dump_file) {
2061 JitCodeLoadRecord record;
2062 size_t nameLen = strlen (jinfo->d.method->name);
2063 memset (&record, 0, sizeof (record));
2065 add_basic_JitCodeLoadRecord_info (&record);
2066 record.header.total_size = sizeof (record) + nameLen + 1 + jinfo->code_size;
2067 record.vma = (guint64)jinfo->code_start;
2068 record.code_addr = (guint64)jinfo->code_start;
2069 record.code_size = (guint64)jinfo->code_size;
2071 mono_os_mutex_lock (&perf_dump_mutex);
2073 record.code_index = ++code_index;
2075 // TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held).
2077 record.header.timestamp = mono_clock_get_time_ns (clock_id);
2079 fwrite (&record, sizeof (record), 1, perf_dump_file);
2080 fwrite (jinfo->d.method->name, nameLen + 1, 1, perf_dump_file);
2081 fwrite (code, jinfo->code_size, 1, perf_dump_file);
2083 mono_os_mutex_unlock (&perf_dump_mutex);
2087 static void
2088 add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record)
2090 record->header.id = JIT_CODE_LOAD;
2091 record->header.timestamp = mono_clock_get_time_ns (clock_id);
2092 record->pid = perf_dump_pid;
2093 record->tid = syscall (SYS_gettid);
2096 void
2097 mono_jit_dump_cleanup (void)
2099 if (perf_dump_mmap_addr != MAP_FAILED)
2100 munmap (perf_dump_mmap_addr, sizeof(FileHeader));
2101 if (perf_dump_file)
2102 fclose (perf_dump_file);
2105 #else
2107 void
2108 mono_enable_jit_dump (void)
2112 void
2113 mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2117 void
2118 mono_jit_dump_cleanup (void)
2122 #endif
2124 static void
2125 no_gsharedvt_in_wrapper (void)
2127 g_assert_not_reached ();
2131 Overall algorithm:
2133 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.
2134 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
2135 Dependency management in this case is too complex to justify implementing it.
2137 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
2139 TODO:
2140 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
2141 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
2142 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
2143 Maybe pool JitCompilationEntry, specially those with an inited cond var;
2145 typedef struct {
2146 MonoMethod *method;
2147 MonoDomain *domain;
2148 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
2149 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
2150 int threads_waiting; /* Number of threads waiting on this job */
2151 gboolean has_cond; /* True if @cond was initialized */
2152 gboolean done; /* True if the method finished JIT'ing */
2153 MonoCoopCond cond; /* Cond sleeping threads wait one */
2154 } JitCompilationEntry;
2156 typedef struct {
2157 GPtrArray *in_flight_methods; //JitCompilationEntry*
2158 MonoCoopMutex lock;
2159 } JitCompilationData;
2162 Timeout, in millisecounds, that we wait other threads to finish JITing.
2163 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.
2165 #define MAX_JIT_TIMEOUT_MS 1000
2168 static JitCompilationData compilation_data;
2169 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
2171 static void
2172 mini_jit_init_job_control (void)
2174 mono_coop_mutex_init (&compilation_data.lock);
2175 compilation_data.in_flight_methods = g_ptr_array_new ();
2178 static void
2179 lock_compilation_data (void)
2181 mono_coop_mutex_lock (&compilation_data.lock);
2184 static void
2185 unlock_compilation_data (void)
2187 mono_coop_mutex_unlock (&compilation_data.lock);
2190 static JitCompilationEntry*
2191 find_method (MonoMethod *method, MonoDomain *domain)
2193 int i;
2194 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
2195 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
2196 if (e->method == method && e->domain == domain)
2197 return e;
2200 return NULL;
2203 static void
2204 add_current_thread (MonoJitTlsData *jit_tls)
2206 ++jit_tls->active_jit_methods;
2209 static void
2210 unref_jit_entry (JitCompilationEntry *entry)
2212 --entry->ref_count;
2213 if (entry->ref_count)
2214 return;
2215 if (entry->has_cond)
2216 mono_coop_cond_destroy (&entry->cond);
2217 g_free (entry);
2221 * Returns true if this method waited successfully for another thread to JIT it
2223 static gboolean
2224 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2226 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2227 JitCompilationEntry *entry;
2229 static gboolean inited;
2230 if (!inited) {
2231 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2232 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2233 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2234 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2235 inited = TRUE;
2238 lock_compilation_data ();
2240 if (!(entry = find_method (method, domain))) {
2241 entry = g_new0 (JitCompilationEntry, 1);
2242 entry->method = method;
2243 entry->domain = domain;
2244 entry->compilation_count = entry->ref_count = 1;
2245 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2246 g_assert (find_method (method, domain) == entry);
2247 add_current_thread (jit_tls);
2249 unlock_compilation_data ();
2250 return FALSE;
2251 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2252 //We can't suspend the current thread if it's already JITing a method.
2253 //Dependency management is too compilated and we want to get rid of this anyways.
2255 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2256 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2258 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2259 ++entry->compilation_count;
2260 ++jit_methods_multiple;
2261 ++jit_tls->active_jit_methods;
2263 unlock_compilation_data ();
2264 return FALSE;
2265 } else {
2266 ++jit_methods_waited;
2267 ++entry->ref_count;
2269 if (!entry->has_cond) {
2270 mono_coop_cond_init (&entry->cond);
2271 entry->has_cond = TRUE;
2274 while (TRUE) {
2275 ++entry->threads_waiting;
2277 g_assert (entry->has_cond);
2278 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2279 --entry->threads_waiting;
2281 if (entry->done) {
2282 unref_jit_entry (entry);
2283 unlock_compilation_data ();
2284 return TRUE;
2285 } else {
2286 //We hit the timeout or a spurious wakeup, fallback to JITing
2287 g_assert (entry->ref_count > 1);
2288 unref_jit_entry (entry);
2289 ++jit_spurious_wakeups_or_timeouts;
2291 ++entry->compilation_count;
2292 ++jit_methods_multiple;
2293 ++jit_tls->active_jit_methods;
2295 unlock_compilation_data ();
2296 return FALSE;
2302 static void
2303 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2305 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2307 lock_compilation_data ();
2309 g_assert (jit_tls->active_jit_methods > 0);
2310 --jit_tls->active_jit_methods;
2312 JitCompilationEntry *entry = find_method (method, target_domain);
2313 g_assert (entry); // It would be weird to fail
2314 entry->done = TRUE;
2316 if (entry->threads_waiting) {
2317 g_assert (entry->has_cond);
2318 mono_coop_cond_broadcast (&entry->cond);
2321 if (--entry->compilation_count == 0) {
2322 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2323 unref_jit_entry (entry);
2326 unlock_compilation_data ();
2329 static MonoJitInfo*
2330 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2332 MonoDomain *domain = mono_get_root_domain ();
2333 MonoJitInfo *jinfo;
2334 guint8 *uw_info;
2335 guint32 info_len;
2337 if (info->uw_info) {
2338 uw_info = info->uw_info;
2339 info_len = info->uw_info_len;
2340 } else {
2341 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2344 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2345 jinfo->d.method = wrapper;
2346 jinfo->code_start = info->code;
2347 jinfo->code_size = info->code_size;
2348 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2350 if (!info->uw_info)
2351 g_free (uw_info);
2353 return jinfo;
2356 static gpointer
2357 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2359 MonoJitInfo *jinfo;
2360 gpointer code;
2362 if (mono_llvm_only) {
2363 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2364 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2366 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2368 * These wrappers are only created for signatures which are in the program, but
2369 * sometimes we load methods too eagerly and have to create them even if they
2370 * will never be called.
2372 return (gpointer)no_gsharedvt_in_wrapper;
2377 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2378 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2379 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2381 if (!piinfo->addr) {
2382 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2383 piinfo->addr = mono_lookup_internal_call (method);
2384 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2385 #ifdef HOST_WIN32
2386 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);
2387 #else
2388 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);
2389 #endif
2390 else {
2391 ERROR_DECL (ignored_error);
2392 mono_lookup_pinvoke_call_internal (method, ignored_error);
2393 mono_error_cleanup (ignored_error);
2397 MonoMethod *nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2398 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2399 return_val_if_nok (error, NULL);
2401 code = mono_get_addr_from_ftnptr (compiled_method);
2402 jinfo = mono_jit_info_table_find (target_domain, code);
2403 if (!jinfo)
2404 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2405 if (jinfo)
2406 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2407 return code;
2408 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2409 const char *name = method->name;
2410 char *full_name;
2411 MonoMethod *nm;
2413 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2414 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2415 MonoJitICallInfo *mi = &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor;
2417 * We need to make sure this wrapper
2418 * is compiled because it might end up
2419 * in an (M)RGCTX if generic sharing
2420 * is enabled, and would be called
2421 * indirectly. If it were a
2422 * trampoline we'd try to patch that
2423 * indirect call, which is not
2424 * possible.
2426 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2427 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2428 if (mono_llvm_only) {
2429 nm = mono_marshal_get_delegate_invoke (method, NULL);
2430 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2431 return_val_if_nok (error, NULL);
2432 return mono_get_addr_from_ftnptr (compiled_ptr);
2435 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2436 if (mono_use_interpreter)
2437 return NULL;
2439 return mono_create_delegate_trampoline (target_domain, method->klass);
2440 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2441 nm = mono_marshal_get_delegate_begin_invoke (method);
2442 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2443 return_val_if_nok (error, NULL);
2444 return mono_get_addr_from_ftnptr (compiled_ptr);
2445 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2446 nm = mono_marshal_get_delegate_end_invoke (method);
2447 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2448 return_val_if_nok (error, NULL);
2449 return mono_get_addr_from_ftnptr (compiled_ptr);
2453 full_name = mono_method_full_name (method, TRUE);
2454 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2455 g_free (full_name);
2456 return NULL;
2459 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2460 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2462 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2463 static MonoTrampInfo *in_tinfo, *out_tinfo;
2464 MonoTrampInfo *tinfo;
2465 MonoJitInfo *jinfo;
2466 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2468 if (is_in && in_tinfo)
2469 return in_tinfo->code;
2470 else if (!is_in && out_tinfo)
2471 return out_tinfo->code;
2474 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2475 * works.
2476 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2478 if (mono_ee_features.use_aot_trampolines)
2479 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2480 else
2481 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2482 jinfo = create_jit_info_for_trampoline (method, tinfo);
2483 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2484 if (is_in)
2485 in_tinfo = tinfo;
2486 else
2487 out_tinfo = tinfo;
2488 return tinfo->code;
2492 return NULL;
2495 static gpointer
2496 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2498 MonoDomain *target_domain, *domain = mono_domain_get ();
2499 MonoJitInfo *info;
2500 gpointer code = NULL, p;
2501 MonoJitICallInfo *callinfo = NULL;
2502 WrapperInfo *winfo = NULL;
2503 gboolean use_interp = FALSE;
2505 error_init (error);
2507 if (mono_ee_features.force_use_interpreter && !jit_only)
2508 use_interp = TRUE;
2509 if (!use_interp && mono_interp_only_classes) {
2510 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2511 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2512 use_interp = TRUE;
2515 if (use_interp) {
2516 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2517 if (code)
2518 return code;
2521 if (mono_llvm_only)
2522 /* Should be handled by the caller */
2523 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2526 * ICALL wrappers are handled specially, since there is only one copy of them
2527 * shared by all appdomains.
2529 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2530 winfo = mono_marshal_get_wrapper_info (method);
2531 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2532 callinfo = mono_find_jit_icall_info (winfo->d.icall.jit_icall_id);
2534 /* Must be domain neutral since there is only one copy */
2535 opt |= MONO_OPT_SHARED;
2536 } else {
2537 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2538 opt &= ~MONO_OPT_SHARED;
2541 if (opt & MONO_OPT_SHARED)
2542 target_domain = mono_get_root_domain ();
2543 else
2544 target_domain = domain;
2546 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2547 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2549 g_assert (info);
2550 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2551 MonoGenericContext *ctx = NULL;
2552 if (method->is_inflated)
2553 ctx = mono_method_get_context (method);
2554 method = info->d.synchronized_inner.method;
2555 if (ctx) {
2556 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2557 g_assert (is_ok (error)); /* FIXME don't swallow the error */
2562 lookup_start:
2563 info = lookup_method (target_domain, method);
2564 if (info) {
2565 /* We can't use a domain specific method in another domain */
2566 if (! ((domain != target_domain) && !info->domain_neutral)) {
2567 MonoVTable *vtable;
2569 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2570 vtable = mono_class_vtable_checked (domain, method->klass, error);
2571 if (!is_ok (error))
2572 return NULL;
2573 g_assert (vtable);
2574 if (!mono_runtime_class_init_full (vtable, error))
2575 return NULL;
2576 MONO_PROFILER_RAISE (jit_done, (method, info));
2577 return mono_create_ftnptr (target_domain, info->code_start);
2581 #ifdef MONO_USE_AOT_COMPILER
2582 if (opt & MONO_OPT_AOT) {
2583 MonoDomain *domain = NULL;
2585 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2586 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2587 g_assert (info);
2588 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2589 /* AOT'd wrappers for interp must be owned by root domain */
2590 domain = mono_get_root_domain ();
2593 if (!domain)
2594 domain = mono_domain_get ();
2596 mono_class_init_internal (method->klass);
2598 code = mono_aot_get_method (domain, method, error);
2599 if (code) {
2600 MonoVTable *vtable;
2602 if (mono_gc_is_critical_method (method)) {
2604 * The suspend code needs to be able to lookup these methods by ip in async context,
2605 * so preload their jit info.
2607 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2608 g_assert (ji);
2612 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2613 * This is not a problem, since it will be initialized when the method is first
2614 * called by init_method ().
2616 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2617 vtable = mono_class_vtable_checked (domain, method->klass, error);
2618 mono_error_assert_ok (error);
2619 if (!mono_runtime_class_init_full (vtable, error))
2620 return NULL;
2623 if (!is_ok (error))
2624 return NULL;
2626 #endif
2628 if (!code) {
2629 code = compile_special (method, target_domain, error);
2631 if (!is_ok (error))
2632 return NULL;
2635 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER) {
2636 if (mono_llvm_only) {
2637 /* Signal to the caller that AOTed code is not found */
2638 return NULL;
2640 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2642 if (!is_ok (error))
2643 return NULL;
2646 if (!code) {
2647 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2648 char *full_name = mono_type_get_full_name (method->klass);
2649 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2650 g_free (full_name);
2651 return NULL;
2654 if (mono_aot_only) {
2655 char *fullname = mono_method_get_full_name (method);
2656 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);
2657 g_free (fullname);
2659 return NULL;
2662 if (wait_or_register_method_to_compile (method, target_domain))
2663 goto lookup_start;
2664 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2665 unregister_method_for_compile (method, target_domain);
2667 if (!is_ok (error))
2668 return NULL;
2670 if (!code && mono_llvm_only) {
2671 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2672 g_assert_not_reached ();
2675 if (!code)
2676 return NULL;
2678 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2679 #ifndef HOST_WASM
2680 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2681 MonoDomain *d;
2684 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2686 MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2687 g_assert (ji);
2689 #endif
2691 p = mono_create_ftnptr (target_domain, code);
2693 if (callinfo) {
2694 // FIXME Locking here is somewhat historical due to mono_register_jit_icall_wrapper taking loader lock.
2695 // atomic_compare_exchange should suffice.
2696 mono_loader_lock ();
2697 mono_jit_lock ();
2698 if (!callinfo->wrapper) {
2699 callinfo->wrapper = p;
2701 mono_jit_unlock ();
2702 mono_loader_unlock ();
2705 // FIXME p or callinfo->wrapper or does not matter?
2706 return p;
2709 gpointer
2710 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2712 gpointer code;
2714 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2715 return code;
2719 * mono_jit_compile_method_jit_only:
2721 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2723 gpointer
2724 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2726 gpointer code;
2728 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2729 return code;
2732 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2733 static void
2734 invalidated_delegate_trampoline (char *desc)
2736 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2737 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2738 desc);
2740 #endif
2743 * mono_jit_free_method:
2745 * Free all memory allocated by the JIT for METHOD.
2747 static void
2748 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2750 MonoJitDynamicMethodInfo *ji;
2751 gboolean destroy = TRUE, removed;
2752 GHashTableIter iter;
2753 MonoJumpList *jlist;
2754 MonoJitDomainInfo *info = domain_jit_info (domain);
2756 g_assert (method->dynamic);
2758 if (mono_use_interpreter) {
2759 mini_get_interp_callbacks ()->free_method (domain, method);
2762 mono_domain_lock (domain);
2763 ji = mono_dynamic_code_hash_lookup (domain, method);
2764 mono_domain_unlock (domain);
2766 if (!ji)
2767 return;
2769 mono_debug_remove_method (method, domain);
2770 mono_lldb_remove_method (domain, method, ji);
2772 mono_domain_lock (domain);
2773 g_hash_table_remove (info->dynamic_code_hash, method);
2774 mono_domain_jit_code_hash_lock (domain);
2775 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2776 g_assert (removed);
2777 mono_domain_jit_code_hash_unlock (domain);
2778 g_hash_table_remove (info->jump_trampoline_hash, method);
2779 g_hash_table_remove (info->seq_points, method);
2781 ji->ji->seq_points = NULL;
2783 /* requires the domain lock - took above */
2784 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2786 /* Remove jump targets in this method */
2787 g_hash_table_iter_init (&iter, info->jump_target_hash);
2788 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2789 GSList *tmp, *remove;
2791 remove = NULL;
2792 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2793 guint8 *ip = (guint8 *)tmp->data;
2795 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2796 remove = g_slist_prepend (remove, tmp);
2798 for (tmp = remove; tmp; tmp = tmp->next) {
2799 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2801 g_slist_free (remove);
2803 mono_domain_unlock (domain);
2805 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2806 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2808 * Instead of freeing the code, change it to call an error routine
2809 * so people can fix their code.
2811 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2812 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2814 g_free (type);
2815 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2816 destroy = FALSE;
2818 #endif
2821 * This needs to be done before freeing code_mp, since the code address is the
2822 * key in the table, so if we free the code_mp first, another thread can grab the
2823 * same code address and replace our entry in the table.
2825 mono_jit_info_table_remove (domain, ji->ji);
2827 if (destroy)
2828 mono_code_manager_destroy (ji->code_mp);
2829 g_free (ji);
2832 gpointer
2833 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2835 gpointer code;
2836 MonoJitInfo *ji;
2838 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2839 if (!code) {
2840 ERROR_DECL (oerror);
2842 /* Might be AOTed code */
2843 mono_class_init_internal (method->klass);
2844 code = mono_aot_get_method (domain, method, oerror);
2845 if (code) {
2846 mono_error_assert_ok (oerror);
2847 ji = mono_jit_info_table_find (domain, code);
2848 } else {
2849 if (!is_ok (oerror))
2850 mono_error_cleanup (oerror);
2852 /* Might be interpreted */
2853 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2857 *out_ji = ji;
2859 return code;
2862 gpointer
2863 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2865 MonoDomain *target_domain;
2866 MonoJitInfo *info;
2868 if (default_opt & MONO_OPT_SHARED)
2869 target_domain = mono_get_root_domain ();
2870 else
2871 target_domain = domain;
2873 info = lookup_method (target_domain, method);
2874 if (info) {
2875 /* We can't use a domain specific method in another domain */
2876 if (! ((domain != target_domain) && !info->domain_neutral)) {
2877 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2878 if (ji)
2879 *ji = info;
2880 return info->code_start;
2884 if (ji)
2885 *ji = NULL;
2886 return NULL;
2889 static guint32 bisect_opt = 0;
2890 static GHashTable *bisect_methods_hash = NULL;
2892 void
2893 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2895 FILE *file;
2896 char method_name [2048];
2898 bisect_opt = opt;
2899 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2900 g_assert (bisect_methods_hash);
2902 file = fopen (method_list_filename, "r");
2903 g_assert (file);
2905 while (fgets (method_name, sizeof (method_name), file)) {
2906 size_t len = strlen (method_name);
2907 g_assert (len > 0);
2908 g_assert (method_name [len - 1] == '\n');
2909 method_name [len - 1] = 0;
2910 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2912 g_assert (feof (file));
2915 gboolean mono_do_single_method_regression = FALSE;
2916 guint32 mono_single_method_regression_opt = 0;
2917 MonoMethod *mono_current_single_method;
2918 GSList *mono_single_method_list;
2919 GHashTable *mono_single_method_hash;
2921 guint32
2922 mono_get_optimizations_for_method (MonoMethod *method, guint32 opt)
2924 g_assert (method);
2926 if (bisect_methods_hash) {
2927 char *name = mono_method_full_name (method, TRUE);
2928 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2929 g_free (name);
2930 if (res)
2931 return opt | bisect_opt;
2933 if (!mono_do_single_method_regression)
2934 return opt;
2935 if (!mono_current_single_method) {
2936 if (!mono_single_method_hash)
2937 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2938 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2939 g_hash_table_insert (mono_single_method_hash, method, method);
2940 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2942 return opt;
2944 if (method == mono_current_single_method)
2945 return mono_single_method_regression_opt;
2946 return opt;
2949 gpointer
2950 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2952 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2955 typedef struct {
2956 MonoMethod *method;
2957 gpointer compiled_method;
2958 gpointer runtime_invoke;
2959 MonoVTable *vtable;
2960 MonoDynCallInfo *dyn_call_info;
2961 MonoClass *ret_box_class;
2962 MonoMethodSignature *sig;
2963 gboolean gsharedvt_invoke;
2964 gboolean use_interp;
2965 gpointer *wrapper_arg;
2966 } RuntimeInvokeInfo;
2968 static RuntimeInvokeInfo*
2969 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2971 MonoMethod *invoke;
2972 RuntimeInvokeInfo *info = NULL;
2973 RuntimeInvokeInfo *ret = NULL;
2975 info = g_new0 (RuntimeInvokeInfo, 1);
2976 info->compiled_method = compiled_method;
2977 info->use_interp = use_interp;
2978 if (mono_llvm_only && method->string_ctor)
2979 info->sig = mono_marshal_get_string_ctor_signature (method);
2980 else
2981 info->sig = mono_method_signature_internal (method);
2983 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2984 (void)invoke;
2985 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2986 if (!is_ok (error))
2987 goto exit;
2988 g_assert (info->vtable);
2990 MonoMethodSignature *sig;
2991 sig = info->sig;
2992 MonoType *ret_type;
2995 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2996 * in full-aot mode, so we use a slower, but more generic wrapper if
2997 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2999 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3000 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
3001 gboolean supported = TRUE;
3002 int i;
3004 if (method->string_ctor)
3005 sig = mono_marshal_get_string_ctor_signature (method);
3007 for (i = 0; i < sig->param_count; ++i) {
3008 MonoType *t = sig->params [i];
3010 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
3011 supported = FALSE;
3014 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
3015 supported = FALSE;
3017 if (supported) {
3018 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
3019 if (mini_debug_options.dyn_runtime_invoke)
3020 g_assert (info->dyn_call_info);
3023 #endif
3025 ret_type = sig->ret;
3026 switch (ret_type->type) {
3027 case MONO_TYPE_VOID:
3028 break;
3029 case MONO_TYPE_I1:
3030 case MONO_TYPE_U1:
3031 case MONO_TYPE_I2:
3032 case MONO_TYPE_U2:
3033 case MONO_TYPE_I4:
3034 case MONO_TYPE_U4:
3035 case MONO_TYPE_I:
3036 case MONO_TYPE_U:
3037 case MONO_TYPE_I8:
3038 case MONO_TYPE_U8:
3039 case MONO_TYPE_BOOLEAN:
3040 case MONO_TYPE_CHAR:
3041 case MONO_TYPE_R4:
3042 case MONO_TYPE_R8:
3043 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3044 break;
3045 case MONO_TYPE_PTR:
3046 info->ret_box_class = mono_defaults.int_class;
3047 break;
3048 case MONO_TYPE_STRING:
3049 case MONO_TYPE_CLASS:
3050 case MONO_TYPE_ARRAY:
3051 case MONO_TYPE_SZARRAY:
3052 case MONO_TYPE_OBJECT:
3053 break;
3054 case MONO_TYPE_GENERICINST:
3055 if (!MONO_TYPE_IS_REFERENCE (ret_type))
3056 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3057 break;
3058 case MONO_TYPE_VALUETYPE:
3059 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3060 break;
3061 default:
3062 g_assert_not_reached ();
3063 break;
3066 if (info->use_interp) {
3067 ret = info;
3068 info = NULL;
3069 goto exit;
3072 if (!info->dyn_call_info) {
3073 if (mono_llvm_only) {
3074 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
3075 g_assert_not_reached ();
3076 #endif
3077 info->gsharedvt_invoke = TRUE;
3078 if (!callee_gsharedvt) {
3079 /* Invoke a gsharedvt out wrapper instead */
3080 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
3081 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
3083 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
3084 info->wrapper_arg [0] = mini_llvmonly_add_method_wrappers (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
3086 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
3087 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
3088 g_free (wrapper_sig);
3090 info->compiled_method = mono_jit_compile_method (wrapper, error);
3091 if (!is_ok (error))
3092 goto exit;
3093 } else {
3094 /* Gsharedvt methods can be invoked the same way */
3095 /* The out wrapper has the same signature as the compiled gsharedvt method */
3096 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
3098 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
3100 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
3101 g_free (wrapper_sig);
3104 info->runtime_invoke = mono_jit_compile_method (invoke, error);
3105 if (!is_ok (error))
3106 goto exit;
3109 ret = info;
3110 info = NULL;
3111 exit:
3112 g_free (info);
3113 return ret;
3116 static MonoObject*
3117 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
3119 MonoMethodSignature *sig = info->sig;
3120 MonoDomain *domain = mono_domain_get ();
3121 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
3122 gpointer retval_ptr;
3123 guint8 retval [256];
3124 int i, pindex;
3126 error_init (error);
3128 g_assert (info->gsharedvt_invoke);
3131 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
3132 * The advantage of this is the gsharedvt out wrappers have a reduced set of
3133 * signatures, so we only have to generate runtime invoke wrappers for these
3134 * signatures.
3135 * This code also handles invocation of gsharedvt methods directly, no
3136 * out wrappers are used in that case.
3138 // allocate param_refs = param_count and args = param_count + hasthis + 2.
3139 int const param_count = sig->param_count;
3140 gpointer* const param_refs = g_newa (gpointer, param_count * 2 + sig->hasthis + 2);
3141 gpointer* const args = param_refs + param_count;
3142 pindex = 0;
3144 * The runtime invoke wrappers expects pointers to primitive types, so have to
3145 * use indirections.
3147 if (sig->hasthis)
3148 args [pindex ++] = &obj;
3149 if (sig->ret->type != MONO_TYPE_VOID) {
3150 retval_ptr = &retval;
3151 args [pindex ++] = &retval_ptr;
3153 for (i = 0; i < sig->param_count; ++i) {
3154 MonoType *t = sig->params [i];
3156 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
3157 MonoClass *klass = mono_class_from_mono_type_internal (t);
3158 guint8 *nullable_buf;
3159 int size;
3161 size = mono_class_value_size (klass, NULL);
3162 nullable_buf = g_alloca (size);
3163 g_assert (nullable_buf);
3165 /* The argument pointed to by params [i] is either a boxed vtype or null */
3166 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
3167 params [i] = nullable_buf;
3170 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
3171 param_refs [i] = params [i];
3172 params [i] = &(param_refs [i]);
3174 args [pindex ++] = &params [i];
3176 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
3177 args [pindex ++] = &info->wrapper_arg;
3179 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3181 runtime_invoke (NULL, args, exc, info->compiled_method);
3182 if (exc && *exc)
3183 return NULL;
3185 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
3186 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3187 else
3188 return *(MonoObject**)retval;
3192 * mono_jit_runtime_invoke:
3193 * \param method: the method to invoke
3194 * \param obj: this pointer
3195 * \param params: array of parameter values.
3196 * \param exc: Set to the exception raised in the managed method.
3197 * \param error: error or caught exception object
3198 * If \p exc is NULL, \p error is thrown instead.
3199 * If coop is enabled, \p exc argument is ignored -
3200 * all exceptions are caught and propagated through \p error
3202 static MonoObject*
3203 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
3205 MonoMethod *invoke, *callee;
3206 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
3207 MonoDomain *domain = mono_domain_get ();
3208 MonoJitDomainInfo *domain_info;
3209 RuntimeInvokeInfo *info, *info2;
3210 MonoJitInfo *ji = NULL;
3211 gboolean callee_gsharedvt = FALSE;
3213 if (mono_ee_features.force_use_interpreter)
3214 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3216 error_init (error);
3217 if (exc)
3218 *exc = NULL;
3220 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
3221 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3222 return NULL;
3225 domain_info = domain_jit_info (domain);
3227 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3229 if (!info) {
3230 if (mono_security_core_clr_enabled ()) {
3232 * This might be redundant since mono_class_vtable () already does this,
3233 * but keep it just in case for moonlight.
3235 mono_class_setup_vtable (method->klass);
3236 if (mono_class_has_failure (method->klass)) {
3237 mono_error_set_for_class_failure (error, method->klass);
3238 if (exc)
3239 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3240 return NULL;
3244 gpointer compiled_method;
3246 callee = method;
3247 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3248 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3250 * Array Get/Set/Address methods. The JIT implements them using inline code
3251 * inside the runtime invoke wrappers, so no need to compile them.
3253 if (mono_aot_only) {
3255 * Call a wrapper, since the runtime invoke wrapper was not generated.
3257 MonoMethod *wrapper;
3259 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3260 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3261 callee = wrapper;
3262 } else {
3263 callee = NULL;
3267 gboolean use_interp = FALSE;
3269 if (callee) {
3270 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3271 if (!compiled_method) {
3272 g_assert (!is_ok (error));
3274 if (mono_use_interpreter)
3275 use_interp = TRUE;
3276 else
3277 return NULL;
3278 } else {
3279 if (mono_llvm_only) {
3280 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3281 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3282 if (callee_gsharedvt)
3283 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3286 if (!callee_gsharedvt)
3287 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3289 } else {
3290 compiled_method = NULL;
3293 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3294 if (!is_ok (error))
3295 return NULL;
3297 mono_domain_lock (domain);
3298 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3299 mono_domain_unlock (domain);
3300 if (info2) {
3301 g_free (info);
3302 info = info2;
3307 * We need this here because mono_marshal_get_runtime_invoke can place
3308 * the helper method in System.Object and not the target class.
3310 if (!mono_runtime_class_init_full (info->vtable, error)) {
3311 if (exc)
3312 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3313 return NULL;
3316 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3317 we always catch the exception and propagate it through the MonoError */
3318 gboolean catchExcInMonoError =
3319 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3320 MonoObject *invoke_exc = NULL;
3321 if (catchExcInMonoError)
3322 exc = &invoke_exc;
3324 /* The wrappers expect this to be initialized to NULL */
3325 if (exc)
3326 *exc = NULL;
3328 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3329 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3330 if (info->dyn_call_info) {
3331 if (!dyn_runtime_invoke) {
3332 mono_domain_lock (domain);
3334 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3335 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3336 if (!dyn_runtime_invoke && mono_use_interpreter) {
3337 info->use_interp = TRUE;
3338 info->dyn_call_info = NULL;
3339 } else if (!is_ok (error)) {
3340 mono_domain_unlock (domain);
3341 return NULL;
3343 mono_domain_unlock (domain);
3346 if (info->dyn_call_info) {
3347 MonoMethodSignature *sig = mono_method_signature_internal (method);
3348 gpointer *args;
3349 int i, pindex, buf_size;
3350 guint8 *buf;
3351 guint8 retval [256];
3353 /* Convert the arguments to the format expected by start_dyn_call () */
3354 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3355 pindex = 0;
3356 if (sig->hasthis)
3357 args [pindex ++] = &obj;
3358 for (i = 0; i < sig->param_count; ++i) {
3359 MonoType *t = sig->params [i];
3361 if (t->byref) {
3362 args [pindex ++] = &params [i];
3363 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3364 args [pindex ++] = &params [i];
3365 } else {
3366 args [pindex ++] = params [i];
3370 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3372 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3373 buf = g_alloca (buf_size);
3374 memset (buf, 0, buf_size);
3375 g_assert (buf);
3377 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3379 dyn_runtime_invoke (buf, exc, info->compiled_method);
3380 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3382 if (catchExcInMonoError && *exc != NULL) {
3383 mono_error_set_exception_instance (error, (MonoException*) *exc);
3384 return NULL;
3387 if (info->ret_box_class)
3388 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3389 else
3390 return *(MonoObject**)retval;
3392 #endif
3394 MonoObject *result;
3396 if (info->use_interp) {
3397 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3398 return_val_if_nok (error, NULL);
3399 } else if (mono_llvm_only) {
3400 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3401 if (!is_ok (error))
3402 return NULL;
3403 } else {
3404 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3406 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3408 if (catchExcInMonoError && *exc != NULL) {
3409 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3410 mono_error_set_exception_instance (error, (MonoException*) *exc);
3412 return result;
3415 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3417 MonoException *exc = NULL;
3418 MonoJitInfo *ji;
3419 MonoContext mctx;
3420 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3421 MONO_SIG_HANDLER_GET_CONTEXT;
3423 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3425 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3427 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3428 if (mono_arch_is_int_overflow (ctx, info))
3430 * The spec says this throws ArithmeticException, but MS throws the derived
3431 * OverflowException.
3433 exc = mono_get_exception_overflow ();
3434 else
3435 exc = mono_get_exception_divide_by_zero ();
3436 #else
3437 exc = mono_get_exception_divide_by_zero ();
3438 #endif
3440 if (!ji) {
3441 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3442 goto exit;
3444 mono_sigctx_to_monoctx (ctx, &mctx);
3445 if (mono_dump_start ())
3446 mono_handle_native_crash (mono_get_signame (SIGFPE), &mctx, info);
3447 if (mono_do_crash_chaining) {
3448 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3449 goto exit;
3453 mono_arch_handle_exception (ctx, exc);
3455 exit:
3456 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3459 MONO_SIG_HANDLER_FUNC (, mono_crashing_signal_handler)
3461 MonoContext mctx;
3462 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3463 MONO_SIG_HANDLER_GET_CONTEXT;
3465 if (mono_runtime_get_no_exec ())
3466 exit (1);
3468 mono_sigctx_to_monoctx (ctx, &mctx);
3469 if (mono_dump_start ())
3470 #if defined(HAVE_SIG_INFO) && !defined(HOST_WIN32) // info is a siginfo_t
3471 mono_handle_native_crash (mono_get_signame (info->si_signo), &mctx, info);
3472 #else
3473 mono_handle_native_crash (mono_get_signame (SIGTERM), &mctx, info);
3474 #endif
3475 if (mono_do_crash_chaining) {
3476 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3477 return;
3481 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3483 #define HAVE_SIG_INFO
3484 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3486 #ifdef MONO_SIG_HANDLER_DEBUG
3487 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3488 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3489 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3490 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3491 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3492 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3493 #endif
3495 #endif
3497 gboolean
3498 mono_is_addr_implicit_null_check (void *addr)
3500 /* implicit null checks are only expected to work on the first page. larger
3501 * offsets are expected to have an explicit null check */
3502 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3505 // This function is separate from mono_sigsegv_signal_handler
3506 // so debug_fault_addr can be seen in debugger stacks.
3507 #ifdef MONO_SIG_HANDLER_DEBUG
3508 MONO_NEVER_INLINE
3509 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3510 #else
3511 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3512 #endif
3514 MonoJitInfo *ji = NULL;
3515 MonoDomain *domain = mono_domain_get ();
3516 gpointer fault_addr = NULL;
3517 MonoContext mctx;
3519 #if defined(HAVE_SIG_INFO) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3520 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3521 #endif
3522 #ifdef HAVE_SIG_INFO
3523 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3524 #else
3525 void *info = NULL;
3526 #endif
3527 MONO_SIG_HANDLER_GET_CONTEXT;
3529 mono_sigctx_to_monoctx (ctx, &mctx);
3531 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3532 if (mono_arch_is_single_step_event (info, ctx)) {
3533 mini_get_dbg_callbacks ()->single_step_event (ctx);
3534 return;
3535 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3536 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3537 return;
3539 #endif
3541 #if defined(HAVE_SIG_INFO)
3542 #if !defined(HOST_WIN32)
3543 fault_addr = info->si_addr;
3544 if (mono_aot_is_pagefault (info->si_addr)) {
3545 mono_aot_handle_pagefault (info->si_addr);
3546 return;
3548 int signo = info->si_signo;
3549 #else
3550 int signo = SIGSEGV;
3551 #endif
3553 /* The thread might no be registered with the runtime */
3554 if (!mono_domain_get () || !jit_tls) {
3555 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3556 return;
3557 if (mono_dump_start())
3558 mono_handle_native_crash (mono_get_signame (signo), &mctx, info);
3559 if (mono_do_crash_chaining) {
3560 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3561 return;
3564 #endif
3566 if (domain)
3567 ji = mono_jit_info_table_find_internal (domain, mono_arch_ip_from_context (ctx), TRUE, TRUE);
3569 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3570 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3571 return;
3573 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3574 fault_addr = info->si_addr;
3575 if (fault_addr == NULL) {
3576 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3579 if (jit_tls && jit_tls->stack_size &&
3580 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3582 * The hard-guard page has been hit: there is not much we can do anymore
3583 * Print a hopefully clear message and abort.
3585 mono_handle_hard_stack_ovf (jit_tls, ji, &mctx, (guint8*)info->si_addr);
3586 g_assert_not_reached ();
3587 } else {
3588 /* The original handler might not like that it is executed on an altstack... */
3589 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3590 return;
3592 #ifdef TARGET_AMD64
3593 /* exceptions-amd64.c handles the check itself */
3594 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3595 #else
3596 if (mono_is_addr_implicit_null_check (info->si_addr)) {
3597 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3598 } else {
3599 // FIXME: This shouldn't run on the altstack
3600 if (mono_dump_start ())
3601 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, info);
3603 #endif
3605 #else
3607 if (!ji) {
3608 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3609 return;
3611 if (mono_dump_start ())
3612 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3614 if (mono_do_crash_chaining) {
3615 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3616 return;
3620 if (mono_is_addr_implicit_null_check (fault_addr)) {
3621 mono_arch_handle_exception (ctx, NULL);
3622 } else {
3623 if (mono_dump_start ())
3624 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3625 if (mono_do_crash_chaining) {
3626 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3627 return;
3630 #endif
3633 #ifdef MONO_SIG_HANDLER_DEBUG
3635 // This function is separate from mono_sigsegv_signal_handler_debug
3636 // so debug_fault_addr can be seen in debugger stacks.
3637 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3639 #ifdef HOST_WIN32
3640 gpointer const debug_fault_addr = (gpointer)MONO_SIG_HANDLER_GET_INFO () ->ep->ExceptionRecord->ExceptionInformation [1];
3641 #elif defined (HAVE_SIG_INFO)
3642 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3643 #else
3644 #error No extra parameter is passed, not even 0, to avoid any confusion.
3645 #endif
3646 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3649 #endif // MONO_SIG_HANDLER_DEBUG
3651 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3653 MonoException *exc;
3654 MONO_SIG_HANDLER_GET_CONTEXT;
3656 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3658 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3660 mono_arch_handle_exception (ctx, exc);
3662 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3665 #ifndef DISABLE_REMOTING
3666 /* mono_jit_create_remoting_trampoline:
3667 * @method: pointer to the method info
3669 * Creates a trampoline which calls the remoting functions. This
3670 * is used in the vtable of transparent proxies.
3672 * Returns: a pointer to the newly created code
3674 static gpointer
3675 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3677 MonoMethod *nm;
3678 guint8 *addr = NULL;
3680 error_init (error);
3682 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3683 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3684 domain, NULL);
3687 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3688 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3689 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3690 else
3691 nm = method;
3692 return_val_if_nok (error, NULL);
3693 addr = (guint8 *)mono_compile_method_checked (nm, error);
3694 return_val_if_nok (error, NULL);
3695 return mono_get_addr_from_ftnptr (addr);
3697 #endif
3699 static G_GNUC_UNUSED void
3700 no_imt_trampoline (void)
3702 g_assert_not_reached ();
3705 static G_GNUC_UNUSED void
3706 no_vcall_trampoline (void)
3708 g_assert_not_reached ();
3711 static gpointer *vtable_trampolines;
3712 static int vtable_trampolines_size;
3714 gpointer
3715 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3717 int index = slot_index + MONO_IMT_SIZE;
3719 if (mono_llvm_only)
3720 return mini_llvmonly_get_vtable_trampoline (vt, slot_index, index);
3722 g_assert (slot_index >= - MONO_IMT_SIZE);
3723 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3724 mono_jit_lock ();
3725 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3726 int new_size;
3727 gpointer new_table;
3729 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3730 while (new_size <= index)
3731 new_size *= 2;
3732 new_table = g_new0 (gpointer, new_size);
3734 if (vtable_trampolines)
3735 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3736 g_free (vtable_trampolines);
3737 mono_memory_barrier ();
3738 vtable_trampolines = (void **)new_table;
3739 vtable_trampolines_size = new_size;
3741 mono_jit_unlock ();
3744 if (!vtable_trampolines [index])
3745 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3746 return vtable_trampolines [index];
3749 static gpointer
3750 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3752 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3755 static gboolean
3756 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3758 if (mono_llvm_only)
3759 return FALSE;
3761 gpointer *imt = (gpointer*)vt;
3762 imt -= MONO_IMT_SIZE;
3764 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3767 static gpointer
3768 create_delegate_method_ptr (MonoMethod *method, MonoError *error)
3770 gpointer func;
3772 if (method_is_dynamic (method)) {
3773 /* Creating a trampoline would leak memory */
3774 func = mono_compile_method_checked (method, error);
3775 return_val_if_nok (error, NULL);
3776 } else {
3777 gpointer trampoline = mono_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
3778 return_val_if_nok (error, NULL);
3779 func = mono_create_ftnptr (mono_domain_get (), trampoline);
3781 return func;
3784 static void
3785 mini_init_delegate (MonoDelegateHandle delegate, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
3787 MonoDelegate *del = MONO_HANDLE_RAW (delegate);
3788 MonoDomain *domain = MONO_HANDLE_DOMAIN (delegate);
3790 if (!method) {
3791 MonoJitInfo *ji;
3793 g_assert (addr);
3794 ji = mono_jit_info_table_find_internal (domain, mono_get_addr_from_ftnptr (addr), TRUE, TRUE);
3795 /* Shared code */
3796 if (!ji && domain != mono_get_root_domain ())
3797 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr), TRUE, TRUE);
3798 if (ji) {
3799 if (ji->is_trampoline) {
3800 /* Could be an unbox trampoline etc. */
3801 method = ji->d.tramp_info->method;
3802 } else {
3803 method = mono_jit_info_get_method (ji);
3804 g_assert (!mono_class_is_gtd (method->klass));
3809 if (method)
3810 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
3812 if (addr)
3813 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
3815 #ifndef DISABLE_REMOTING
3816 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
3817 if (mono_use_interpreter) {
3818 MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, mini_get_interp_callbacks ()->get_remoting_invoke (method, addr, error));
3819 } else {
3820 g_assert (method);
3821 method = mono_marshal_get_remoting_invoke (method, error);
3822 return_if_nok (error);
3823 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
3825 return_if_nok (error);
3827 #endif
3829 MONO_HANDLE_SET (delegate, target, target);
3830 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, mono_create_delegate_trampoline (domain, mono_handle_class (delegate)));
3832 if (mono_use_interpreter) {
3833 mini_get_interp_callbacks ()->init_delegate (del, error);
3834 return_if_nok (error);
3837 if (mono_llvm_only) {
3838 g_assert (del->method);
3839 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3840 del->method_ptr = mini_llvmonly_load_method_delegate (del->method, FALSE, FALSE, &del->extra_arg, error);
3841 } else if (!del->method_ptr) {
3842 del->method_ptr = create_delegate_method_ptr (del->method, error);
3843 return_if_nok (error);
3847 char*
3848 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3850 int abs_offset;
3852 abs_offset = offset;
3853 if (abs_offset < 0)
3854 abs_offset = - abs_offset;
3855 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3858 gpointer
3859 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3861 gboolean is_virtual_generic, is_interface, load_imt_reg;
3862 int offset, idx;
3864 static guint8 **cache = NULL;
3865 static int cache_size = 0;
3867 if (!method)
3868 return NULL;
3870 if (MONO_TYPE_ISSTRUCT (sig->ret))
3871 return NULL;
3873 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3874 is_interface = mono_class_is_interface (method->klass);
3875 load_imt_reg = is_virtual_generic || is_interface;
3877 if (is_interface)
3878 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3879 else
3880 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3882 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3883 g_assert (idx >= 0);
3885 /* Resize the cache to idx + 1 */
3886 if (cache_size < idx + 1) {
3887 mono_jit_lock ();
3888 if (cache_size < idx + 1) {
3889 guint8 **new_cache;
3890 int new_cache_size = idx + 1;
3892 new_cache = g_new0 (guint8*, new_cache_size);
3893 if (cache)
3894 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3895 g_free (cache);
3897 mono_memory_barrier ();
3898 cache = new_cache;
3899 cache_size = new_cache_size;
3901 mono_jit_unlock ();
3904 if (cache [idx])
3905 return cache [idx];
3907 /* FIXME Support more cases */
3908 if (mono_ee_features.use_aot_trampolines) {
3909 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3910 g_assert (cache [idx]);
3911 } else {
3912 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3914 return cache [idx];
3918 * mini_parse_debug_option:
3919 * @option: The option to parse.
3921 * Parses debug options for the mono runtime. The options are the same as for
3922 * the MONO_DEBUG environment variable.
3925 gboolean
3926 mini_parse_debug_option (const char *option)
3928 // Empty string is ok as consequence of appending ",foo"
3929 // without first checking for empty.
3930 if (*option == 0)
3931 return TRUE;
3933 if (!strcmp (option, "handle-sigint"))
3934 mini_debug_options.handle_sigint = TRUE;
3935 else if (!strcmp (option, "keep-delegates"))
3936 mini_debug_options.keep_delegates = TRUE;
3937 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3938 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3939 else if (!strcmp (option, "collect-pagefault-stats"))
3940 mini_debug_options.collect_pagefault_stats = TRUE;
3941 else if (!strcmp (option, "break-on-unverified"))
3942 mini_debug_options.break_on_unverified = TRUE;
3943 else if (!strcmp (option, "no-gdb-backtrace"))
3944 mini_debug_options.no_gdb_backtrace = TRUE;
3945 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3946 mini_debug_options.suspend_on_native_crash = TRUE;
3947 else if (!strcmp (option, "suspend-on-exception"))
3948 mini_debug_options.suspend_on_exception = TRUE;
3949 else if (!strcmp (option, "suspend-on-unhandled"))
3950 mini_debug_options.suspend_on_unhandled = TRUE;
3951 else if (!strcmp (option, "dont-free-domains"))
3952 mono_dont_free_domains = TRUE;
3953 else if (!strcmp (option, "dyn-runtime-invoke"))
3954 mini_debug_options.dyn_runtime_invoke = TRUE;
3955 else if (!strcmp (option, "gdb"))
3956 mini_debug_options.gdb = TRUE;
3957 else if (!strcmp (option, "lldb"))
3958 mini_debug_options.lldb = TRUE;
3959 else if (!strcmp (option, "llvm-disable-inlining"))
3960 mini_debug_options.llvm_disable_inlining = TRUE;
3961 else if (!strcmp (option, "llvm-disable-implicit-null-checks"))
3962 mini_debug_options.llvm_disable_implicit_null_checks = TRUE;
3963 else if (!strcmp (option, "explicit-null-checks"))
3964 mini_debug_options.explicit_null_checks = TRUE;
3965 else if (!strcmp (option, "gen-seq-points"))
3966 mini_debug_options.gen_sdb_seq_points = TRUE;
3967 else if (!strcmp (option, "gen-compact-seq-points"))
3968 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3969 else if (!strcmp (option, "no-compact-seq-points"))
3970 mini_debug_options.no_seq_points_compact_data = TRUE;
3971 else if (!strcmp (option, "single-imm-size"))
3972 mini_debug_options.single_imm_size = TRUE;
3973 else if (!strcmp (option, "init-stacks"))
3974 mini_debug_options.init_stacks = TRUE;
3975 else if (!strcmp (option, "casts"))
3976 mini_debug_options.better_cast_details = TRUE;
3977 else if (!strcmp (option, "soft-breakpoints"))
3978 mini_debug_options.soft_breakpoints = TRUE;
3979 else if (!strcmp (option, "check-pinvoke-callconv"))
3980 mini_debug_options.check_pinvoke_callconv = TRUE;
3981 else if (!strcmp (option, "use-fallback-tls"))
3982 mini_debug_options.use_fallback_tls = TRUE;
3983 else if (!strcmp (option, "debug-domain-unload"))
3984 mono_enable_debug_domain_unload (TRUE);
3985 else if (!strcmp (option, "partial-sharing"))
3986 mono_set_partial_sharing_supported (TRUE);
3987 else if (!strcmp (option, "align-small-structs"))
3988 mono_align_small_structs = TRUE;
3989 else if (!strcmp (option, "native-debugger-break"))
3990 mini_debug_options.native_debugger_break = TRUE;
3991 else if (!strcmp (option, "disable_omit_fp"))
3992 mini_debug_options.disable_omit_fp = TRUE;
3993 // This is an internal testing feature.
3994 // Every tail. encountered is required to be optimized.
3995 // It is asserted.
3996 else if (!strcmp (option, "test-tailcall-require"))
3997 mini_debug_options.test_tailcall_require = TRUE;
3998 else if (!strcmp (option, "verbose-gdb"))
3999 mini_debug_options.verbose_gdb = TRUE;
4000 else if (!strcmp (option, "clr-memory-model"))
4001 // FIXME Kill this debug flag
4002 mini_debug_options.weak_memory_model = FALSE;
4003 else if (!strcmp (option, "weak-memory-model"))
4004 mini_debug_options.weak_memory_model = TRUE;
4005 else if (!strcmp (option, "top-runtime-invoke-unhandled"))
4006 mini_debug_options.top_runtime_invoke_unhandled = TRUE;
4007 else if (!strncmp (option, "thread-dump-dir=", 16))
4008 mono_set_thread_dump_dir(g_strdup(option + 16));
4009 else if (!strncmp (option, "aot-skip=", 9)) {
4010 mini_debug_options.aot_skip_set = TRUE;
4011 mini_debug_options.aot_skip = atoi (option + 9);
4012 } else
4013 return FALSE;
4015 return TRUE;
4018 static void
4019 mini_parse_debug_options (void)
4021 char *options = g_getenv ("MONO_DEBUG");
4022 gchar **args, **ptr;
4024 if (!options)
4025 return;
4027 args = g_strsplit (options, ",", -1);
4028 g_free (options);
4030 for (ptr = args; ptr && *ptr; ptr++) {
4031 const char *arg = *ptr;
4033 if (!mini_parse_debug_option (arg)) {
4034 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
4035 // test-tailcall-require is also accepted but not documented.
4036 // empty string is also accepted and ignored as a consequence
4037 // of appending ",foo" without checking for empty.
4038 fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break', 'thread-dump-dir=DIR', 'no-verbose-gdb', 'llvm_disable_inlining', 'llvm-disable-self-init', 'llvm-disable-implicit-null-checks', 'weak-memory-model'.\n");
4039 exit (1);
4043 g_strfreev (args);
4046 MonoDebugOptions *
4047 mini_get_debug_options (void)
4049 return &mini_debug_options;
4052 static gpointer
4053 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
4055 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4056 gpointer* desc = NULL;
4058 if ((desc = (gpointer*)g_hash_table_lookup (domain->ftnptrs_hash, addr)))
4059 return desc;
4060 #if defined(__mono_ppc64__)
4061 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
4063 desc [0] = addr;
4064 desc [1] = NULL;
4065 desc [2] = NULL;
4066 # endif
4067 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
4068 return desc;
4069 #else
4070 return addr;
4071 #endif
4074 static gpointer
4075 mini_get_addr_from_ftnptr (gpointer descr)
4077 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4078 return *(gpointer*)descr;
4079 #else
4080 return descr;
4081 #endif
4084 static void
4085 register_jit_stats (void)
4087 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
4088 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
4089 mono_counters_register ("Methods from AOT+LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot_llvm);
4090 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
4091 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
4092 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
4093 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_method_to_ir);
4094 mono_counters_register ("JIT/liveness_handle_exception_clauses", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_liveness_handle_exception_clauses);
4095 mono_counters_register ("JIT/handle_out_of_line_bblock", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_out_of_line_bblock);
4096 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_long_opts);
4097 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_typechecks);
4098 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop);
4099 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_emulate_ops);
4100 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches);
4101 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs);
4102 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce);
4103 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_alias_analysis);
4104 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_if_conversion);
4105 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_bb_ordering);
4106 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compile_dominator_info);
4107 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compute_natural_loops);
4108 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_insert_safepoints);
4109 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_compute);
4110 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_cprop);
4111 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_deadce);
4112 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_perform_abc_removal);
4113 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_remove);
4114 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop2);
4115 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs2);
4116 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce2);
4117 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches2);
4118 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_vtype_opts);
4119 mono_counters_register ("JIT/decompose_array_access_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_array_access_opts);
4120 mono_counters_register ("JIT/liveness_handle_exception_clauses2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
4121 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_analyze_liveness);
4122 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_linear_scan);
4123 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_arch_allocate_vars);
4124 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_spill_global_vars);
4125 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop3);
4126 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce3);
4127 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_codegen);
4128 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_create_jit_info);
4129 mono_counters_register ("JIT/gc_create_gc_map", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_gc_create_gc_map);
4130 mono_counters_register ("JIT/save_seq_point_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_save_seq_point_info);
4131 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_time);
4132 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
4133 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
4134 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
4135 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
4136 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
4137 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
4138 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
4139 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
4140 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
4141 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
4142 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
4143 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
4144 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
4145 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
4146 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
4147 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
4148 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
4149 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
4152 static void runtime_invoke_info_free (gpointer value);
4154 static gint
4155 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
4157 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
4158 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
4160 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
4163 static guint
4164 class_method_pair_hash (gconstpointer data)
4166 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
4168 return (gsize)pair->klass ^ (gsize)pair->method;
4171 static void
4172 mini_create_jit_domain_info (MonoDomain *domain)
4174 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
4176 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4177 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4178 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
4179 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4180 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
4181 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
4182 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
4183 info->jump_target_hash = g_hash_table_new (NULL, NULL);
4184 mono_jit_code_hash_init (&info->interp_code_hash);
4186 domain->runtime_info = info;
4189 static void
4190 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
4192 MonoJumpList *jlist = (MonoJumpList *)value;
4193 g_slist_free ((GSList*)jlist->list);
4196 static void
4197 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
4199 GSList *list = (GSList *)value;
4200 g_slist_free (list);
4203 static void
4204 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
4206 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
4207 mono_code_manager_destroy (di->code_mp);
4208 g_free (di);
4211 static void
4212 runtime_invoke_info_free (gpointer value)
4214 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
4216 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4217 if (info->dyn_call_info)
4218 mono_arch_dyn_call_free (info->dyn_call_info);
4219 #endif
4220 g_free (info);
4223 static void
4224 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
4226 g_slist_free ((GSList*)value);
4229 static void
4230 mini_free_jit_domain_info (MonoDomain *domain)
4232 MonoJitDomainInfo *info = domain_jit_info (domain);
4234 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
4235 g_hash_table_destroy (info->jump_target_hash);
4236 if (info->jump_target_got_slot_hash) {
4237 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
4238 g_hash_table_destroy (info->jump_target_got_slot_hash);
4240 if (info->dynamic_code_hash) {
4241 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
4242 g_hash_table_destroy (info->dynamic_code_hash);
4244 g_hash_table_destroy (info->method_code_hash);
4245 g_hash_table_destroy (info->jump_trampoline_hash);
4246 g_hash_table_destroy (info->jit_trampoline_hash);
4247 g_hash_table_destroy (info->delegate_trampoline_hash);
4248 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
4249 g_hash_table_destroy (info->mrgctx_hash);
4250 g_hash_table_destroy (info->method_rgctx_hash);
4251 g_hash_table_destroy (info->interp_method_pointer_hash);
4252 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
4253 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
4254 g_hash_table_destroy (info->seq_points);
4255 g_hash_table_destroy (info->arch_seq_points);
4256 if (info->agent_info)
4257 mini_get_dbg_callbacks ()->free_domain_info (domain);
4258 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
4259 if (info->llvm_jit_callees) {
4260 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
4261 g_hash_table_destroy (info->llvm_jit_callees);
4263 mono_internal_hash_table_destroy (&info->interp_code_hash);
4264 #ifdef ENABLE_LLVM
4265 mono_llvm_free_domain_info (domain);
4266 #endif
4268 g_free (domain->runtime_info);
4269 domain->runtime_info = NULL;
4272 #ifdef ENABLE_LLVM
4273 static gboolean
4274 llvm_init_inner (void)
4276 mono_llvm_init (!mono_compile_aot);
4277 return TRUE;
4279 #endif
4282 * mini_llvm_init:
4284 * Load and initialize LLVM support.
4285 * Return TRUE on success.
4287 gboolean
4288 mini_llvm_init (void)
4290 #ifdef ENABLE_LLVM
4291 static gboolean llvm_inited;
4292 static gboolean init_result;
4294 mono_loader_lock_if_inited ();
4295 if (!llvm_inited) {
4296 init_result = llvm_init_inner ();
4297 llvm_inited = TRUE;
4299 mono_loader_unlock_if_inited ();
4300 return init_result;
4301 #else
4302 return FALSE;
4303 #endif
4306 void
4307 mini_add_profiler_argument (const char *desc)
4309 if (!profile_options)
4310 profile_options = g_ptr_array_new ();
4312 g_ptr_array_add (profile_options, (gpointer) g_strdup (desc));
4316 const MonoEECallbacks *mono_interp_callbacks_pointer;
4318 void
4319 mini_install_interp_callbacks (const MonoEECallbacks *cbs)
4321 mono_interp_callbacks_pointer = cbs;
4324 static MonoDebuggerCallbacks dbg_cbs;
4326 void
4327 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4329 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4330 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4333 MonoDebuggerCallbacks*
4334 mini_get_dbg_callbacks (void)
4336 return &dbg_cbs;
4340 mono_ee_api_version (void)
4342 return MONO_EE_API_VERSION;
4345 void
4346 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4348 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4351 void
4352 mono_interp_to_native_trampoline (gpointer addr, gpointer ccontext)
4354 mini_get_interp_callbacks ()->to_native_trampoline (addr, ccontext);
4357 static gboolean
4358 mini_is_interpreter_enabled (void)
4360 return mono_use_interpreter;
4363 static const char*
4364 mono_get_runtime_build_version (void);
4366 MonoDomain *
4367 mini_init (const char *filename, const char *runtime_version)
4369 ERROR_DECL (error);
4370 MonoDomain *domain;
4372 MonoRuntimeCallbacks callbacks;
4374 static const MonoThreadInfoRuntimeCallbacks ticallbacks = {
4375 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK, mono)
4378 MONO_VES_INIT_BEGIN ();
4380 CHECKED_MONO_INIT ();
4382 #if defined(__linux__)
4383 if (access ("/proc/self/maps", F_OK) != 0) {
4384 g_print ("Mono requires /proc to be mounted.\n");
4385 exit (1);
4387 #endif
4389 mono_interp_stub_init ();
4390 #ifndef DISABLE_INTERPRETER
4391 if (mono_use_interpreter)
4392 mono_ee_interp_init (mono_interp_opts_string);
4393 #endif
4395 mono_debugger_agent_stub_init ();
4396 #ifndef DISABLE_SDB
4397 mono_debugger_agent_init ();
4398 #endif
4400 if (sdb_options)
4401 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4403 mono_os_mutex_init_recursive (&jit_mutex);
4405 mono_cross_helpers_run ();
4407 mono_counters_init ();
4409 mini_jit_init ();
4411 mini_jit_init_job_control ();
4413 /* Happens when using the embedding interface */
4414 if (!default_opt_set)
4415 default_opt = mono_parse_default_optimizations (NULL);
4417 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4418 if (mono_aot_only)
4419 mono_set_generic_sharing_vt_supported (TRUE);
4420 #else
4421 if (mono_llvm_only)
4422 mono_set_generic_sharing_vt_supported (TRUE);
4423 #endif
4425 mono_tls_init_runtime_keys ();
4427 if (!global_codeman)
4428 global_codeman = mono_code_manager_new ();
4430 memset (&callbacks, 0, sizeof (callbacks));
4431 callbacks.create_ftnptr = mini_create_ftnptr;
4432 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4433 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4434 callbacks.get_runtime_build_version = mono_get_runtime_build_version;
4435 callbacks.set_cast_details = mono_set_cast_details;
4436 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4437 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4438 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4439 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4440 callbacks.imt_entry_inited = mini_imt_entry_inited;
4441 callbacks.init_delegate = mini_init_delegate;
4442 #define JIT_INVOKE_WORKS
4443 #ifdef JIT_INVOKE_WORKS
4444 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4445 #endif
4446 #define JIT_TRAMPOLINES_WORK
4447 #ifdef JIT_TRAMPOLINES_WORK
4448 callbacks.compile_method = mono_jit_compile_method;
4449 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4450 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4451 callbacks.free_method = mono_jit_free_method;
4452 #ifndef DISABLE_REMOTING
4453 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4454 #endif
4455 #endif
4456 #ifndef DISABLE_REMOTING
4457 if (mono_use_interpreter)
4458 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4459 #endif
4460 callbacks.is_interpreter_enabled = mini_is_interpreter_enabled;
4461 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4463 #ifndef DISABLE_CRASH_REPORTING
4464 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4465 #endif
4467 mono_install_callbacks (&callbacks);
4469 #ifndef HOST_WIN32
4470 mono_w32handle_init ();
4471 #endif
4473 mono_thread_info_runtime_init (&ticallbacks);
4475 if (g_hasenv ("MONO_DEBUG")) {
4476 mini_parse_debug_options ();
4479 mono_code_manager_init ();
4481 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4483 static const MonoCodeManagerCallbacks code_manager_callbacks = {
4485 #undef MONO_CODE_MANAGER_CALLBACK
4486 #define MONO_CODE_MANAGER_CALLBACK(ret, name, sig) mono_arch_code_ ## name,
4487 MONO_CODE_MANAGER_CALLBACKS
4491 mono_code_manager_install_callbacks (&code_manager_callbacks);
4492 #endif
4494 mono_hwcap_init ();
4496 mono_arch_cpu_init ();
4498 mono_arch_init ();
4500 mono_unwind_init ();
4502 if (mini_debug_options.lldb || g_hasenv ("MONO_LLDB")) {
4503 mono_lldb_init ("");
4504 mono_dont_free_domains = TRUE;
4507 #ifdef XDEBUG_ENABLED
4508 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4509 if (mono_xdebug) {
4510 mono_xdebug_init (mono_xdebug);
4511 g_free (mono_xdebug);
4512 /* So methods for multiple domains don't have the same address */
4513 mono_dont_free_domains = TRUE;
4514 mono_using_xdebug = TRUE;
4515 } else if (mini_debug_options.gdb) {
4516 mono_xdebug_init ((char*)"gdb");
4517 mono_dont_free_domains = TRUE;
4518 mono_using_xdebug = TRUE;
4520 #endif
4522 #ifdef ENABLE_LLVM
4523 if (mono_use_llvm)
4524 mono_llvm_init (!mono_compile_aot);
4525 #endif
4527 mono_trampolines_init ();
4529 if (default_opt & MONO_OPT_AOT)
4530 mono_aot_init ();
4532 mini_get_dbg_callbacks ()->init ();
4534 #ifdef TARGET_WASM
4535 mono_wasm_debugger_init ();
4536 #endif
4538 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4539 mono_set_generic_sharing_supported (TRUE);
4540 #endif
4542 mono_thread_info_signals_init ();
4544 mono_init_native_crash_info ();
4546 #ifndef MONO_CROSS_COMPILE
4547 mono_runtime_install_handlers ();
4548 #endif
4549 mono_threads_install_cleanup (mini_thread_cleanup);
4551 #ifdef JIT_TRAMPOLINES_WORK
4552 mono_install_create_domain_hook (mini_create_jit_domain_info);
4553 mono_install_free_domain_hook (mini_free_jit_domain_info);
4554 #endif
4555 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4556 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4557 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4559 mono_profiler_state.context_enable = mini_profiler_context_enable;
4560 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4561 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4562 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4563 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4564 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4566 if (g_hasenv ("MONO_PROFILE")) {
4567 gchar *profile_env = g_getenv ("MONO_PROFILE");
4568 mini_add_profiler_argument (profile_env);
4569 g_free (profile_env);
4572 if (profile_options)
4573 for (guint i = 0; i < profile_options->len; i++)
4574 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4576 mono_profiler_started ();
4578 if (mini_debug_options.collect_pagefault_stats)
4579 mono_aot_set_make_unreadable (TRUE);
4581 if (runtime_version)
4582 domain = mono_init_version (filename, runtime_version);
4583 else
4584 domain = mono_init_from_assembly (filename, filename);
4586 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
4587 if (mono_compile_aot)
4588 ds_server_disable ();
4590 ep_init ();
4591 #endif
4593 if (mono_aot_only) {
4594 /* This helps catch code allocation requests */
4595 mono_code_manager_set_read_only (mono_domain_ambient_memory_manager (domain)->code_mp);
4596 mono_marshal_use_aot_wrappers (TRUE);
4599 if (mono_llvm_only) {
4600 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline);
4601 mono_set_always_build_imt_trampolines (TRUE);
4602 } else if (mono_aot_only) {
4603 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4604 } else {
4605 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4608 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4609 mono_arch_finish_init ();
4611 /* This must come after mono_init () in the aot-only case */
4612 mono_exceptions_init ();
4614 /* This should come after mono_init () too */
4615 mini_gc_init ();
4617 mono_create_icall_signatures ();
4619 register_jit_stats ();
4621 #define JIT_CALLS_WORK
4622 #ifdef JIT_CALLS_WORK
4623 /* Needs to be called here since register_jit_icall depends on it */
4624 mono_marshal_init ();
4626 mono_arch_register_lowlevel_calls ();
4628 register_icalls ();
4630 mono_generic_sharing_init ();
4631 #endif
4633 #ifdef MONO_ARCH_SIMD_INTRINSICS
4634 mono_simd_intrinsics_init ();
4635 #endif
4637 #ifndef ENABLE_NETCORE
4638 mono_tasklets_init ();
4639 #endif
4641 register_trampolines (domain);
4643 if (mono_compile_aot)
4645 * Avoid running managed code when AOT compiling, since the platform
4646 * might only support aot-only execution.
4648 mono_runtime_set_no_exec (TRUE);
4650 mono_mem_account_register_counters ();
4652 #define JIT_RUNTIME_WORKS
4653 #ifdef JIT_RUNTIME_WORKS
4654 mono_install_runtime_cleanup (runtime_cleanup);
4655 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4656 mono_error_assert_ok (error);
4657 mono_thread_internal_attach (domain);
4658 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4659 #endif
4660 mono_threads_set_runtime_startup_finished ();
4662 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
4663 ep_finish_init ();
4664 #endif
4666 #ifdef ENABLE_EXPERIMENT_TIERED
4667 if (!mono_compile_aot) {
4668 /* create compilation thread in background */
4669 mini_tiered_init ();
4671 #endif
4673 if (mono_profiler_sampling_enabled ())
4674 mono_runtime_setup_stat_profiler ();
4676 MONO_PROFILER_RAISE (runtime_initialized, ());
4678 MONO_VES_INIT_END ();
4680 return domain;
4683 static void
4684 register_icalls (void)
4686 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4687 ves_icall_get_frame_info);
4688 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4689 ves_icall_get_trace);
4690 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4691 mono_runtime_install_handlers);
4692 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4693 mono_runtime_cleanup_handlers);
4695 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4696 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4697 mini_get_dbg_callbacks ()->unhandled_exception);
4698 #endif
4701 * It's important that we pass `TRUE` as the last argument here, as
4702 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4703 * *did* emit a wrapper, we'd be looking at infinite recursion since
4704 * the wrapper would call the icall which would call the wrapper and
4705 * so on.
4707 register_icall (mono_profiler_raise_method_enter, mono_icall_sig_void_ptr_ptr, TRUE);
4708 register_icall (mono_profiler_raise_method_leave, mono_icall_sig_void_ptr_ptr, TRUE);
4709 register_icall (mono_profiler_raise_method_tail_call, mono_icall_sig_void_ptr_ptr, TRUE);
4710 register_icall (mono_profiler_raise_exception_clause, mono_icall_sig_void_ptr_int_int_object, TRUE);
4712 register_icall (mono_trace_enter_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4713 register_icall (mono_trace_leave_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4714 register_icall (mono_trace_tail_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4715 g_assert (mono_get_lmf_addr == mono_tls_get_lmf_addr);
4716 register_icall (mono_jit_set_domain, mono_icall_sig_void_ptr, TRUE);
4717 register_icall (mono_domain_get, mono_icall_sig_ptr, TRUE);
4719 register_icall (mono_llvm_throw_exception, mono_icall_sig_void_object, TRUE);
4720 register_icall (mono_llvm_rethrow_exception, mono_icall_sig_void_object, TRUE);
4721 register_icall (mono_llvm_resume_exception, mono_icall_sig_void, TRUE);
4722 register_icall (mono_llvm_match_exception, mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
4723 register_icall (mono_llvm_clear_exception, NULL, TRUE);
4724 register_icall (mono_llvm_load_exception, mono_icall_sig_object, TRUE);
4725 register_icall (mono_llvm_throw_corlib_exception, mono_icall_sig_void_int, TRUE);
4726 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4727 register_icall (mono_llvm_set_unhandled_exception_handler, NULL, TRUE);
4729 // FIXME: This is broken
4730 #ifndef TARGET_WASM
4731 register_icall (mono_debug_personality, mono_icall_sig_int_int_int_ptr_ptr_ptr, TRUE);
4732 #endif
4733 #endif
4735 if (!mono_llvm_only) {
4736 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception, mono_icall_sig_void_object, TRUE);
4737 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception, mono_icall_sig_void_object, TRUE);
4738 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception, mono_icall_sig_void_ptr, TRUE);
4740 register_icall (mono_thread_get_undeniable_exception, mono_icall_sig_object, FALSE);
4741 register_icall (ves_icall_thread_finish_async_abort, mono_icall_sig_void, FALSE);
4742 register_icall (mono_thread_interruption_checkpoint, mono_icall_sig_object, FALSE);
4743 register_icall (mono_thread_force_interruption_checkpoint_noraise, mono_icall_sig_object, FALSE);
4745 register_icall (mono_threads_state_poll, mono_icall_sig_void, FALSE);
4747 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4748 register_opcode_emulation (OP_LMUL, __emul_lmul, mono_icall_sig_long_long_long, mono_llmult, FALSE);
4749 register_opcode_emulation (OP_LDIV, __emul_ldiv, mono_icall_sig_long_long_long, mono_lldiv, FALSE);
4750 register_opcode_emulation (OP_LDIV_UN, __emul_ldiv_un, mono_icall_sig_long_long_long, mono_lldiv_un, FALSE);
4751 register_opcode_emulation (OP_LREM, __emul_lrem, mono_icall_sig_long_long_long, mono_llrem, FALSE);
4752 register_opcode_emulation (OP_LREM_UN, __emul_lrem_un, mono_icall_sig_long_long_long, mono_llrem_un, FALSE);
4753 #endif
4754 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4755 register_opcode_emulation (OP_LMUL_OVF_UN, __emul_lmul_ovf_un, mono_icall_sig_long_long_long, mono_llmult_ovf_un, FALSE);
4756 register_opcode_emulation (OP_LMUL_OVF, __emul_lmul_ovf, mono_icall_sig_long_long_long, mono_llmult_ovf, FALSE);
4757 #endif
4759 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4760 register_opcode_emulation (OP_LSHL, __emul_lshl, mono_icall_sig_long_long_int32, mono_lshl, TRUE);
4761 register_opcode_emulation (OP_LSHR, __emul_lshr, mono_icall_sig_long_long_int32, mono_lshr, TRUE);
4762 register_opcode_emulation (OP_LSHR_UN, __emul_lshr_un, mono_icall_sig_long_long_int32, mono_lshr_un, TRUE);
4763 #endif
4765 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4766 register_opcode_emulation (OP_IDIV, __emul_op_idiv, mono_icall_sig_int32_int32_int32, mono_idiv, FALSE);
4767 register_opcode_emulation (OP_IDIV_UN, __emul_op_idiv_un, mono_icall_sig_int32_int32_int32, mono_idiv_un, FALSE);
4768 register_opcode_emulation (OP_IREM, __emul_op_irem, mono_icall_sig_int32_int32_int32, mono_irem, FALSE);
4769 register_opcode_emulation (OP_IREM_UN, __emul_op_irem_un, mono_icall_sig_int32_int32_int32, mono_irem_un, FALSE);
4770 #endif
4772 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4773 register_opcode_emulation (OP_IMUL, __emul_op_imul, mono_icall_sig_int32_int32_int32, mono_imul, TRUE);
4774 #endif
4776 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4777 register_opcode_emulation (OP_IMUL_OVF, __emul_op_imul_ovf, mono_icall_sig_int32_int32_int32, mono_imul_ovf, FALSE);
4778 register_opcode_emulation (OP_IMUL_OVF_UN, __emul_op_imul_ovf_un, mono_icall_sig_int32_int32_int32, mono_imul_ovf_un, FALSE);
4779 #endif
4781 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4782 register_opcode_emulation (OP_FDIV, __emul_fdiv, mono_icall_sig_double_double_double, mono_fdiv, FALSE);
4783 #endif
4785 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4786 register_opcode_emulation (OP_FCONV_TO_U8, __emul_fconv_to_u8, mono_icall_sig_ulong_double, mono_fconv_u8_2, FALSE);
4787 register_opcode_emulation (OP_RCONV_TO_U8, __emul_rconv_to_u8, mono_icall_sig_ulong_float, mono_rconv_u8, FALSE);
4788 #endif
4789 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4790 register_opcode_emulation (OP_FCONV_TO_U4, __emul_fconv_to_u4, mono_icall_sig_uint32_double, mono_fconv_u4_2, FALSE);
4791 register_opcode_emulation (OP_RCONV_TO_U4, __emul_rconv_to_u4, mono_icall_sig_uint32_float, mono_rconv_u4, FALSE);
4792 #endif
4793 register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, FALSE);
4794 register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
4795 register_opcode_emulation (OP_RCONV_TO_OVF_I8, __emul_rconv_to_ovf_i8, mono_icall_sig_long_float, mono_rconv_ovf_i8, FALSE);
4796 register_opcode_emulation (OP_RCONV_TO_OVF_U8, __emul_rconv_to_ovf_u8, mono_icall_sig_ulong_float, mono_rconv_ovf_u8, FALSE);
4798 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4799 register_opcode_emulation (OP_FCONV_TO_I8, __emul_fconv_to_i8, mono_icall_sig_long_double, mono_fconv_i8, FALSE);
4800 register_opcode_emulation (OP_RCONV_TO_I8, __emul_rconv_to_i8, mono_icall_sig_long_float, mono_rconv_i8, FALSE);
4801 #endif
4803 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4804 register_opcode_emulation (OP_ICONV_TO_R_UN, __emul_iconv_to_r_un, mono_icall_sig_double_int32, mono_conv_to_r8_un, FALSE);
4805 #endif
4806 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4807 register_opcode_emulation (OP_LCONV_TO_R8, __emul_lconv_to_r8, mono_icall_sig_double_long, mono_lconv_to_r8, FALSE);
4808 #endif
4809 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4810 register_opcode_emulation (OP_LCONV_TO_R4, __emul_lconv_to_r4, mono_icall_sig_float_long, mono_lconv_to_r4, FALSE);
4811 #endif
4812 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4813 register_opcode_emulation (OP_LCONV_TO_R_UN, __emul_lconv_to_r8_un, mono_icall_sig_double_long, mono_lconv_to_r8_un, FALSE);
4814 #endif
4815 #ifdef MONO_ARCH_EMULATE_FREM
4816 register_opcode_emulation (OP_FREM, __emul_frem, mono_icall_sig_double_double_double, mono_fmod, FALSE);
4817 register_opcode_emulation (OP_RREM, __emul_rrem, mono_icall_sig_float_float_float, fmodf, FALSE);
4818 #endif
4820 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4821 if (mono_arch_is_soft_float ()) {
4822 register_opcode_emulation (OP_FSUB, __emul_fsub, mono_icall_sig_double_double_double, mono_fsub, FALSE);
4823 register_opcode_emulation (OP_FADD, __emul_fadd, mono_icall_sig_double_double_double, mono_fadd, FALSE);
4824 register_opcode_emulation (OP_FMUL, __emul_fmul, mono_icall_sig_double_double_double, mono_fmul, FALSE);
4825 register_opcode_emulation (OP_FNEG, __emul_fneg, mono_icall_sig_double_double, mono_fneg, FALSE);
4826 register_opcode_emulation (OP_ICONV_TO_R8, __emul_iconv_to_r8, mono_icall_sig_double_int32, mono_conv_to_r8, FALSE);
4827 register_opcode_emulation (OP_ICONV_TO_R4, __emul_iconv_to_r4, mono_icall_sig_double_int32, mono_conv_to_r4, FALSE);
4828 register_opcode_emulation (OP_FCONV_TO_R4, __emul_fconv_to_r4, mono_icall_sig_double_double, mono_fconv_r4, FALSE);
4829 register_opcode_emulation (OP_FCONV_TO_I1, __emul_fconv_to_i1, mono_icall_sig_int8_double, mono_fconv_i1, FALSE);
4830 register_opcode_emulation (OP_FCONV_TO_I2, __emul_fconv_to_i2, mono_icall_sig_int16_double, mono_fconv_i2, FALSE);
4831 register_opcode_emulation (OP_FCONV_TO_I4, __emul_fconv_to_i4, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4832 register_opcode_emulation (OP_FCONV_TO_U1, __emul_fconv_to_u1, mono_icall_sig_uint8_double, mono_fconv_u1, FALSE);
4833 register_opcode_emulation (OP_FCONV_TO_U2, __emul_fconv_to_u2, mono_icall_sig_uint16_double, mono_fconv_u2, FALSE);
4835 #if TARGET_SIZEOF_VOID_P == 4
4836 register_opcode_emulation (OP_FCONV_TO_I, __emul_fconv_to_i, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4837 #endif
4839 register_opcode_emulation (OP_FBEQ, __emul_fcmp_eq, mono_icall_sig_uint32_double_double, mono_fcmp_eq, FALSE);
4840 register_opcode_emulation (OP_FBLT, __emul_fcmp_lt, mono_icall_sig_uint32_double_double, mono_fcmp_lt, FALSE);
4841 register_opcode_emulation (OP_FBGT, __emul_fcmp_gt, mono_icall_sig_uint32_double_double, mono_fcmp_gt, FALSE);
4842 register_opcode_emulation (OP_FBLE, __emul_fcmp_le, mono_icall_sig_uint32_double_double, mono_fcmp_le, FALSE);
4843 register_opcode_emulation (OP_FBGE, __emul_fcmp_ge, mono_icall_sig_uint32_double_double, mono_fcmp_ge, FALSE);
4844 register_opcode_emulation (OP_FBNE_UN, __emul_fcmp_ne_un, mono_icall_sig_uint32_double_double, mono_fcmp_ne_un, FALSE);
4845 register_opcode_emulation (OP_FBLT_UN, __emul_fcmp_lt_un, mono_icall_sig_uint32_double_double, mono_fcmp_lt_un, FALSE);
4846 register_opcode_emulation (OP_FBGT_UN, __emul_fcmp_gt_un, mono_icall_sig_uint32_double_double, mono_fcmp_gt_un, FALSE);
4847 register_opcode_emulation (OP_FBLE_UN, __emul_fcmp_le_un, mono_icall_sig_uint32_double_double, mono_fcmp_le_un, FALSE);
4848 register_opcode_emulation (OP_FBGE_UN, __emul_fcmp_ge_un, mono_icall_sig_uint32_double_double, mono_fcmp_ge_un, FALSE);
4850 register_opcode_emulation (OP_FCEQ, __emul_fcmp_ceq, mono_icall_sig_uint32_double_double, mono_fceq, FALSE);
4851 register_opcode_emulation (OP_FCGT, __emul_fcmp_cgt, mono_icall_sig_uint32_double_double, mono_fcgt, FALSE);
4852 register_opcode_emulation (OP_FCGT_UN, __emul_fcmp_cgt_un, mono_icall_sig_uint32_double_double, mono_fcgt_un, FALSE);
4853 register_opcode_emulation (OP_FCLT, __emul_fcmp_clt, mono_icall_sig_uint32_double_double, mono_fclt, FALSE);
4854 register_opcode_emulation (OP_FCLT_UN, __emul_fcmp_clt_un, mono_icall_sig_uint32_double_double, mono_fclt_un, FALSE);
4856 register_icall (mono_fload_r4, mono_icall_sig_double_ptr, FALSE);
4857 register_icall (mono_fstore_r4, mono_icall_sig_void_double_ptr, FALSE);
4858 register_icall (mono_fload_r4_arg, mono_icall_sig_uint32_double, FALSE);
4859 register_icall (mono_isfinite_double, mono_icall_sig_int32_double, FALSE);
4861 #endif
4862 register_icall (mono_ckfinite, mono_icall_sig_double_double, FALSE);
4864 #ifdef COMPRESSED_INTERFACE_BITMAP
4865 register_icall (mono_class_interface_match, mono_icall_sig_uint32_ptr_int32, TRUE);
4866 #endif
4868 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4869 #if SIZEOF_REGISTER == 4
4870 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_uint32_double, mono_fconv_u4, TRUE);
4871 #else
4872 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_ulong_double, mono_fconv_u8, TRUE);
4873 #endif
4875 /* other jit icalls */
4876 register_icall (ves_icall_mono_delegate_ctor, mono_icall_sig_void_object_object_ptr, FALSE);
4877 register_icall (ves_icall_mono_delegate_ctor_interp, mono_icall_sig_void_object_object_ptr, FALSE);
4878 register_icall (mono_class_static_field_address,
4879 mono_icall_sig_ptr_ptr_ptr, FALSE);
4880 register_icall (mono_ldtoken_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4881 register_icall (mono_ldtoken_wrapper_generic_shared,
4882 mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4883 register_icall (mono_get_special_static_data, mono_icall_sig_ptr_int, FALSE);
4884 register_icall (ves_icall_mono_ldstr, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4885 register_icall (mono_helper_stelem_ref_check, mono_icall_sig_void_object_object, FALSE);
4886 register_icall (ves_icall_object_new, mono_icall_sig_object_ptr_ptr, FALSE);
4887 register_icall (ves_icall_object_new_specific, mono_icall_sig_object_ptr, FALSE);
4888 register_icall (ves_icall_array_new, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4889 register_icall (ves_icall_array_new_specific, mono_icall_sig_object_ptr_int32, FALSE);
4890 register_icall (ves_icall_runtime_class_init, mono_icall_sig_void_ptr, FALSE);
4891 register_icall (mono_ldftn, mono_icall_sig_ptr_ptr, FALSE);
4892 register_icall (mono_ldvirtfn, mono_icall_sig_ptr_object_ptr, FALSE);
4893 register_icall (mono_ldvirtfn_gshared, mono_icall_sig_ptr_object_ptr, FALSE);
4894 register_icall (mono_helper_compile_generic_method, mono_icall_sig_ptr_object_ptr_ptr, FALSE);
4895 register_icall (mono_helper_ldstr, mono_icall_sig_object_ptr_int, FALSE);
4896 register_icall (mono_helper_ldstr_mscorlib, mono_icall_sig_object_int, FALSE);
4897 register_icall (mono_helper_newobj_mscorlib, mono_icall_sig_object_int, FALSE);
4898 register_icall (mono_value_copy_internal, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
4899 register_icall (mono_object_castclass_unbox, mono_icall_sig_object_object_ptr, FALSE);
4900 register_icall (mono_break, NULL, TRUE);
4901 register_icall (mono_create_corlib_exception_0, mono_icall_sig_object_int, TRUE);
4902 register_icall (mono_create_corlib_exception_1, mono_icall_sig_object_int_object, TRUE);
4903 register_icall (mono_create_corlib_exception_2, mono_icall_sig_object_int_object_object, TRUE);
4904 register_icall (mono_array_new_1, mono_icall_sig_object_ptr_int, FALSE);
4905 register_icall (mono_array_new_2, mono_icall_sig_object_ptr_int_int, FALSE);
4906 register_icall (mono_array_new_3, mono_icall_sig_object_ptr_int_int_int, FALSE);
4907 register_icall (mono_array_new_4, mono_icall_sig_object_ptr_int_int_int_int, FALSE);
4908 register_icall (mono_array_new_n_icall, mono_icall_sig_object_ptr_int_ptr, FALSE);
4909 register_icall (mono_get_native_calli_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4910 register_icall (mono_resume_unwind, mono_icall_sig_void_ptr, TRUE);
4911 register_icall (mono_gsharedvt_constrained_call, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr, FALSE);
4912 register_icall (mono_gsharedvt_value_copy, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4914 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4915 MonoRangeCopyFunction const mono_gc_wbarrier_range_copy = mono_gc_get_range_copy_func ();
4916 register_icall_no_wrapper (mono_gc_wbarrier_range_copy, mono_icall_sig_void_ptr_ptr_int);
4918 register_icall (mono_object_castclass_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4919 register_icall (mono_object_isinst_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4920 register_icall (mono_generic_class_init, mono_icall_sig_void_ptr, FALSE);
4921 register_icall (mono_fill_class_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4922 register_icall (mono_fill_method_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4924 register_dyn_icall (mini_get_dbg_callbacks ()->user_break, mono_debugger_agent_user_break, mono_icall_sig_void, FALSE);
4926 register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_ptr_ptr_ptr, TRUE);
4927 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4928 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4929 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call, mono_icall_sig_ptr_ptr_int_ptr);
4930 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call, mono_icall_sig_ptr_ptr_int_ptr);
4931 /* This needs a wrapper so it can have a preserveall cconv */
4932 register_icall (mini_llvmonly_init_vtable_slot, mono_icall_sig_ptr_ptr_int, FALSE);
4933 register_icall (mini_llvmonly_init_delegate, mono_icall_sig_void_object, TRUE);
4934 register_icall (mini_llvmonly_init_delegate_virtual, mono_icall_sig_void_object_object_ptr, TRUE);
4935 register_icall (mini_llvmonly_throw_nullref_exception, mono_icall_sig_void, TRUE);
4936 register_icall (mini_llvmonly_throw_aot_failed_exception, mono_icall_sig_void_ptr, TRUE);
4938 register_icall (mono_get_assembly_object, mono_icall_sig_object_ptr, TRUE);
4939 register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE);
4940 register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE);
4941 register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE);
4942 register_icall (mono_throw_not_supported, mono_icall_sig_void, FALSE);
4943 register_icall (mono_throw_invalid_program, mono_icall_sig_void_ptr, FALSE);
4944 register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void);
4946 register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);
4947 register_icall_with_wrapper (mono_monitor_enter_v4_internal, mono_icall_sig_void_obj_ptr);
4948 register_icall_no_wrapper (mono_monitor_enter_fast, mono_icall_sig_int_obj);
4949 register_icall_no_wrapper (mono_monitor_enter_v4_fast, mono_icall_sig_int_obj_ptr);
4951 #ifdef TARGET_IOS
4952 register_icall (pthread_getspecific, mono_icall_sig_ptr_ptr, TRUE);
4953 #endif
4954 /* Register tls icalls */
4955 register_icall_no_wrapper (mono_tls_get_thread_extern, mono_icall_sig_ptr);
4956 register_icall_no_wrapper (mono_tls_get_jit_tls_extern, mono_icall_sig_ptr);
4957 register_icall_no_wrapper (mono_tls_get_domain_extern, mono_icall_sig_ptr);
4958 register_icall_no_wrapper (mono_tls_get_sgen_thread_info_extern, mono_icall_sig_ptr);
4959 register_icall_no_wrapper (mono_tls_get_lmf_addr_extern, mono_icall_sig_ptr);
4961 register_icall_no_wrapper (mono_interp_entry_from_trampoline, mono_icall_sig_void_ptr_ptr);
4962 register_icall_no_wrapper (mono_interp_to_native_trampoline, mono_icall_sig_void_ptr_ptr);
4964 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4965 mono_arch_register_icall ();
4966 #endif
4969 MonoJitStats mono_jit_stats = {0};
4972 * Counters of mono_stats and mono_jit_stats can be read without locking during shutdown.
4973 * For all other contexts, assumes that the domain lock is held.
4974 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4976 MONO_NO_SANITIZE_THREAD
4977 void
4978 mono_runtime_print_stats (void)
4980 if (mono_jit_stats.enabled) {
4981 g_print ("Mono Jit statistics\n");
4982 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4983 mono_jit_stats.max_ratio_method);
4984 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4985 mono_jit_stats.biggest_method);
4987 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4988 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4989 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4990 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4991 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4992 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4993 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4994 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4996 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4997 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4998 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
5000 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
5001 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
5002 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
5003 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
5005 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
5006 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
5007 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
5008 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
5009 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
5010 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
5011 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
5012 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
5014 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
5015 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
5016 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
5018 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, NULL);
5019 g_print ("\n");
5023 static void
5024 jit_stats_cleanup (void)
5026 g_free (mono_jit_stats.max_ratio_method);
5027 mono_jit_stats.max_ratio_method = NULL;
5028 g_free (mono_jit_stats.biggest_method);
5029 mono_jit_stats.biggest_method = NULL;
5032 static void
5033 runtime_cleanup (MonoDomain *domain, gpointer user_data)
5035 mini_cleanup (domain);
5038 #ifdef DISABLE_CLEANUP
5039 void
5040 mini_cleanup (MonoDomain *domain)
5042 if (mono_stats.enabled)
5043 g_printf ("Printing runtime stats at shutdown\n");
5044 mono_runtime_print_stats ();
5045 jit_stats_cleanup ();
5046 mono_jit_dump_cleanup ();
5047 mini_get_interp_callbacks ()->cleanup ();
5048 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
5049 ep_shutdown ();
5050 ds_server_shutdown ();
5051 #endif
5053 #else
5054 void
5055 mini_cleanup (MonoDomain *domain)
5057 if (mono_stats.enabled)
5058 g_printf ("Printing runtime stats at shutdown\n");
5059 if (mono_profiler_sampling_enabled ())
5060 mono_runtime_shutdown_stat_profiler ();
5062 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
5064 #ifndef DISABLE_COM
5065 mono_cominterop_release_all_rcws ();
5066 #endif
5068 #ifndef MONO_CROSS_COMPILE
5070 * mono_domain_finalize () needs to be called early since it needs the
5071 * execution engine still fully working (it may invoke managed finalizers).
5073 mono_domain_finalize (domain, 2000);
5074 #endif
5076 /* This accesses metadata so needs to be called before runtime shutdown */
5077 mono_runtime_print_stats ();
5078 jit_stats_cleanup ();
5080 #ifndef MONO_CROSS_COMPILE
5081 mono_runtime_cleanup (domain);
5082 #endif
5084 #ifndef ENABLE_NETCORE
5085 mono_threadpool_cleanup ();
5086 #endif
5088 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
5090 mono_profiler_cleanup ();
5092 if (profile_options) {
5093 for (guint i = 0; i < profile_options->len; ++i)
5094 g_free (g_ptr_array_index (profile_options, i));
5095 g_ptr_array_free (profile_options, TRUE);
5098 mono_icall_cleanup ();
5100 mono_runtime_cleanup_handlers ();
5102 #ifndef MONO_CROSS_COMPILE
5103 mono_domain_free (domain, TRUE);
5104 #endif
5105 free_jit_tls_data (mono_tls_get_jit_tls ());
5107 #ifdef ENABLE_LLVM
5108 if (mono_use_llvm)
5109 mono_llvm_cleanup ();
5110 #endif
5112 mono_aot_cleanup ();
5114 mono_trampolines_cleanup ();
5116 mono_unwind_cleanup ();
5118 mono_code_manager_destroy (global_codeman);
5119 g_free (vtable_trampolines);
5121 mini_jit_cleanup ();
5123 mini_get_interp_callbacks ()->cleanup ();
5125 mono_tramp_info_cleanup ();
5127 mono_arch_cleanup ();
5129 mono_generic_sharing_cleanup ();
5131 mono_cleanup_native_crash_info ();
5133 mono_cleanup ();
5135 mono_trace_cleanup ();
5137 if (mono_inject_async_exc_method)
5138 mono_method_desc_free (mono_inject_async_exc_method);
5140 mono_tls_free_keys ();
5142 mono_os_mutex_destroy (&jit_mutex);
5144 mono_code_manager_cleanup ();
5146 #ifndef HOST_WIN32
5147 mono_w32handle_cleanup ();
5148 #endif
5150 #endif
5152 void
5153 mono_set_defaults (int verbose_level, guint32 opts)
5155 mini_verbose = verbose_level;
5156 mono_set_optimizations (opts);
5159 void
5160 mono_disable_optimizations (guint32 opts)
5162 default_opt &= ~opts;
5165 void
5166 mono_set_optimizations (guint32 opts)
5168 default_opt = opts;
5169 default_opt_set = TRUE;
5170 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
5171 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
5172 #else
5173 if (mono_llvm_only)
5174 mono_set_generic_sharing_vt_supported (TRUE);
5175 #endif
5178 void
5179 mono_set_verbose_level (guint32 level)
5181 mini_verbose = level;
5184 static const char*
5185 mono_get_runtime_build_version (void)
5187 return FULL_VERSION;
5191 * mono_get_runtime_build_info:
5192 * The returned string is owned by the caller. The returned string
5193 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
5194 * \returns the runtime version + build date in string format.
5196 char*
5197 mono_get_runtime_build_info (void)
5199 if (mono_build_date)
5200 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
5201 else
5202 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
5205 static void
5206 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
5208 GHashTable *assemblies = (GHashTable*)user_data;
5209 MonoImage *image = mono_assembly_get_image_internal (ass);
5210 MonoMethod *method, *invoke;
5211 int i, count = 0;
5213 if (g_hash_table_lookup (assemblies, ass))
5214 return;
5216 g_hash_table_insert (assemblies, ass, ass);
5218 if (mini_verbose > 0)
5219 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
5221 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5222 ERROR_DECL (error);
5224 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
5225 if (!method) {
5226 mono_error_cleanup (error); /* FIXME don't swallow the error */
5227 continue;
5229 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
5230 continue;
5231 if (method->is_generic || mono_class_is_gtd (method->klass))
5232 continue;
5234 count++;
5235 if (mini_verbose > 1) {
5236 char * desc = mono_method_full_name (method, TRUE);
5237 g_print ("Compiling %d %s\n", count, desc);
5238 g_free (desc);
5240 mono_compile_method_checked (method, error);
5241 if (!is_ok (error)) {
5242 mono_error_cleanup (error); /* FIXME don't swallow the error */
5243 continue;
5245 if (strcmp (method->name, "Finalize") == 0) {
5246 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
5247 mono_compile_method_checked (invoke, error);
5248 mono_error_assert_ok (error);
5250 #ifndef DISABLE_REMOTING
5251 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
5252 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
5253 mono_error_assert_ok (error);
5254 mono_compile_method_checked (invoke, error);
5255 mono_error_assert_ok (error);
5257 #endif
5260 /* Load and precompile referenced assemblies as well */
5261 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
5262 mono_assembly_load_reference (image, i);
5263 if (image->references [i])
5264 mono_precompile_assembly (image->references [i], assemblies);
5268 void mono_precompile_assemblies ()
5270 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
5272 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
5274 g_hash_table_destroy (assemblies);
5278 * Used by LLVM.
5279 * Have to export this for AOT.
5281 void
5282 mono_personality (void)
5284 /* Not used */
5285 g_assert_not_reached ();
5288 static MonoBreakPolicy
5289 always_insert_breakpoint (MonoMethod *method)
5291 return MONO_BREAK_POLICY_ALWAYS;
5294 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5297 * mono_set_break_policy:
5298 * \param policy_callback the new callback function
5300 * Allow embedders to decide whether to actually obey breakpoint instructions
5301 * (both break IL instructions and \c Debugger.Break method calls), for example
5302 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5303 * untrusted or semi-trusted code.
5305 * \p policy_callback will be called every time a break point instruction needs to
5306 * be inserted with the method argument being the method that calls \c Debugger.Break
5307 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5308 * if it wants the breakpoint to not be effective in the given method.
5309 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5311 void
5312 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5314 if (policy_callback)
5315 break_policy_func = policy_callback;
5316 else
5317 break_policy_func = always_insert_breakpoint;
5320 gboolean
5321 mini_should_insert_breakpoint (MonoMethod *method)
5323 switch (break_policy_func (method)) {
5324 case MONO_BREAK_POLICY_ALWAYS:
5325 return TRUE;
5326 case MONO_BREAK_POLICY_NEVER:
5327 return FALSE;
5328 case MONO_BREAK_POLICY_ON_DBG:
5329 g_warning ("mdb no longer supported");
5330 return FALSE;
5331 default:
5332 g_warning ("Incorrect value returned from break policy callback");
5333 return FALSE;
5337 // Custom handlers currently only implemented by Windows.
5338 #ifndef HOST_WIN32
5339 gboolean
5340 mono_runtime_install_custom_handlers (const char *handlers)
5342 return FALSE;
5345 void
5346 mono_runtime_install_custom_handlers_usage (void)
5348 fprintf (stdout,
5349 "Custom Handlers:\n"
5350 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5351 " separated list of available handlers to install.\n"
5352 "\n"
5353 "No handlers supported on current platform.\n");
5355 #endif /* HOST_WIN32 */