[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mono / mini / mini-runtime.c
blobfdffd5f16c3e801a19783a5cbe8d16c6ad20b0f2
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 <eventpipe/ep.h>
79 #include <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);
170 #ifdef ENABLE_METADATA_UPDATE
171 static void mini_metadata_update_init (MonoError *error);
172 static void mini_invalidate_transformed_interp_methods (MonoDomain *domain, MonoAssemblyLoadContext *alc, uint32_t generation);
173 #endif
176 gboolean
177 mono_running_on_valgrind (void)
179 #ifndef HOST_WIN32
180 if (RUNNING_ON_VALGRIND){
181 #ifdef VALGRIND_JIT_REGISTER_MAP
182 valgrind_register = TRUE;
183 #endif
184 return TRUE;
185 } else
186 #endif
187 return FALSE;
190 void
191 mono_set_use_llvm (mono_bool use_llvm)
193 mono_use_llvm = (gboolean)use_llvm;
197 typedef struct {
198 void *ip;
199 MonoMethod *method;
200 } FindTrampUserData;
202 static void
203 find_tramp (gpointer key, gpointer value, gpointer user_data)
205 FindTrampUserData *ud = (FindTrampUserData*)user_data;
207 if (value == ud->ip)
208 ud->method = (MonoMethod*)key;
211 static char*
212 mono_get_method_from_ip_u (void *ip);
214 /* debug function */
215 char*
216 mono_get_method_from_ip (void *ip)
218 char *result;
219 MONO_ENTER_GC_UNSAFE;
220 result = mono_get_method_from_ip_u (ip);
221 MONO_EXIT_GC_UNSAFE;
222 return result;
225 /* debug function */
226 static char*
227 mono_get_method_from_ip_u (void *ip)
229 MonoJitInfo *ji;
230 MonoMethod *method;
231 char *method_name;
232 char *res;
233 MonoDomain *domain = mono_domain_get ();
234 MonoDebugSourceLocation *location;
235 FindTrampUserData user_data;
237 if (!domain)
238 domain = mono_get_root_domain ();
240 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
241 if (!ji) {
242 user_data.ip = ip;
243 user_data.method = NULL;
244 mono_domain_lock (domain);
245 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
246 mono_domain_unlock (domain);
247 if (user_data.method) {
248 char *mname = mono_method_full_name (user_data.method, TRUE);
249 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
250 g_free (mname);
251 return res;
253 else
254 return NULL;
255 } else if (ji->is_trampoline) {
256 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
257 return res;
260 method = jinfo_get_method (ji);
261 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
262 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
264 char *file_loc = NULL;
265 if (location)
266 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
268 const char *in_interp = ji->is_interp ? " interp" : "";
270 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);
272 mono_debug_free_source_location (location);
273 g_free (method_name);
274 g_free (file_loc);
276 return res;
280 * mono_pmip:
281 * \param ip an instruction pointer address
283 * This method is used from a debugger to get the name of the
284 * method at address \p ip. This routine is typically invoked from
285 * a debugger like this:
287 * (gdb) print mono_pmip ($pc)
289 * \returns the name of the method at address \p ip.
291 G_GNUC_UNUSED char *
292 mono_pmip (void *ip)
294 return mono_get_method_from_ip (ip);
297 G_GNUC_UNUSED char *
298 mono_pmip_u (void *ip)
300 return mono_get_method_from_ip_u (ip);
304 * mono_print_method_from_ip:
305 * \param ip an instruction pointer address
307 * This method is used from a debugger to get the name of the
308 * method at address \p ip.
310 * This prints the name of the method at address \p ip in the standard
311 * output. Unlike \c mono_pmip which returns a string, this routine
312 * prints the value on the standard output.
314 MONO_ATTR_USED void
315 mono_print_method_from_ip (void *ip)
317 MonoJitInfo *ji;
318 char *method;
319 MonoDebugSourceLocation *source;
320 MonoDomain *domain = mono_domain_get ();
321 MonoDomain *target_domain = mono_domain_get ();
322 FindTrampUserData user_data;
323 MonoGenericSharingContext*gsctx;
324 const char *shared_type;
326 if (!domain)
327 domain = mono_get_root_domain ();
328 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
329 if (ji && ji->is_trampoline) {
330 MonoTrampInfo *tinfo = ji->d.tramp_info;
332 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
333 return;
336 if (!ji) {
337 user_data.ip = ip;
338 user_data.method = NULL;
339 mono_domain_lock (domain);
340 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
341 mono_domain_unlock (domain);
343 if (user_data.method) {
344 char *mname = mono_method_full_name (user_data.method, TRUE);
345 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
346 g_free (mname);
347 return;
350 g_print ("No method at %p\n", ip);
351 fflush (stdout);
352 return;
354 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
355 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
357 gsctx = mono_jit_info_get_generic_sharing_context (ji);
358 shared_type = "";
359 if (gsctx) {
360 if (gsctx->is_gsharedvt)
361 shared_type = "gsharedvt ";
362 else
363 shared_type = "gshared ";
366 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);
368 if (source)
369 g_print ("%s:%d\n", source->source_file, source->row);
370 fflush (stdout);
372 mono_debug_free_source_location (source);
373 g_free (method);
377 * mono_method_same_domain:
379 * Determine whenever two compiled methods are in the same domain, thus
380 * the address of the callee can be embedded in the caller.
382 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
384 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
385 return FALSE;
388 * If the call was made from domain-neutral to domain-specific
389 * code, we can't patch the call site.
391 if (caller->domain_neutral && !callee->domain_neutral)
392 return FALSE;
394 MonoMethod *cmethod;
396 cmethod = jinfo_get_method (caller);
397 if ((cmethod->klass == mono_defaults.appdomain_class) &&
398 (strstr (cmethod->name, "InvokeInDomain"))) {
399 /* The InvokeInDomain methods change the current appdomain */
400 return FALSE;
402 return TRUE;
406 * mono_global_codeman_reserve:
408 * Allocate code memory from the global code manager.
410 void *(mono_global_codeman_reserve) (int size)
412 void *ptr;
414 if (mono_aot_only)
415 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
417 if (!global_codeman) {
418 /* This can happen during startup */
419 global_codeman = mono_code_manager_new ();
420 return mono_code_manager_reserve (global_codeman, size);
422 else {
423 mono_jit_lock ();
424 ptr = mono_code_manager_reserve (global_codeman, size);
425 mono_jit_unlock ();
426 return ptr;
430 /* The callback shouldn't take any locks */
431 void
432 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
434 mono_jit_lock ();
435 mono_code_manager_foreach (global_codeman, func, user_data);
436 mono_jit_unlock ();
440 * mono_create_unwind_op:
442 * Create an unwind op with the given parameters.
444 MonoUnwindOp*
445 mono_create_unwind_op (int when, int tag, int reg, int val)
447 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
449 op->op = tag;
450 op->reg = reg;
451 op->val = val;
452 op->when = when;
454 return op;
457 MonoJumpInfoToken *
458 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
460 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
461 res->image = image;
462 res->token = token;
463 res->has_context = context != NULL;
464 if (context)
465 memcpy (&res->context, context, sizeof (MonoGenericContext));
467 return res;
470 MonoJumpInfoToken *
471 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
473 return mono_jump_info_token_new2 (mp, image, token, NULL);
477 * mono_tramp_info_create:
479 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
480 * of JI, and UNWIND_OPS.
482 MonoTrampInfo*
483 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
485 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
487 info->name = g_strdup (name);
488 info->code = code;
489 info->code_size = code_size;
490 info->ji = ji;
491 info->unwind_ops = unwind_ops;
493 return info;
496 void
497 mono_tramp_info_free (MonoTrampInfo *info)
499 g_free (info->name);
501 // FIXME: ji
502 mono_free_unwind_info (info->unwind_ops);
503 if (info->owns_uw_info)
504 g_free (info->uw_info);
505 g_free (info);
508 static void
509 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
511 MonoJitInfo *ji;
513 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
514 mono_jit_info_init (ji, NULL, (guint8*)MINI_FTNPTR_TO_ADDR (info->code), info->code_size, (MonoJitInfoFlags)0, 0, 0);
515 ji->d.tramp_info = info;
516 ji->is_trampoline = TRUE;
518 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
520 mono_jit_info_table_add (domain, ji);
524 * mono_tramp_info_register:
526 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
527 * INFO can be NULL.
528 * Frees INFO.
530 static void
531 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
533 MonoTrampInfo *copy;
535 if (!info)
536 return;
538 if (!domain)
539 domain = mono_get_root_domain ();
541 if (domain)
542 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
543 else
544 copy = g_new0 (MonoTrampInfo, 1);
546 copy->code = info->code;
547 copy->code_size = info->code_size;
548 copy->name = g_strdup (info->name);
549 copy->method = info->method;
551 if (info->unwind_ops) {
552 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
553 copy->owns_uw_info = TRUE;
554 if (domain) {
555 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
556 guint8 *temp = copy->uw_info;
557 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
558 memcpy (copy->uw_info, temp, copy->uw_info_len);
559 g_free (temp);
561 } else {
562 /* Trampolines from aot have the unwind ops already encoded */
563 copy->uw_info = info->uw_info;
564 copy->uw_info_len = info->uw_info_len;
567 mono_save_trampoline_xdebug_info (info);
568 mono_lldb_save_trampoline_info (info);
570 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
571 if (!aot)
572 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
573 #endif
575 if (!domain) {
576 /* If no root domain has been created yet, postpone the registration. */
577 mono_jit_lock ();
578 tramp_infos = g_slist_prepend (tramp_infos, copy);
579 mono_jit_unlock ();
580 } else if (copy->uw_info || info->method) {
581 /* Only register trampolines that have unwind info */
582 register_trampoline_jit_info (domain, copy);
585 if (mono_jit_map_is_enabled ())
586 mono_emit_jit_tramp (info->code, info->code_size, info->name);
588 mono_tramp_info_free (info);
591 void
592 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
594 mono_tramp_info_register_internal (info, domain, FALSE);
597 void
598 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
600 mono_tramp_info_register_internal (info, domain, TRUE);
603 static void
604 mono_tramp_info_cleanup (void)
606 GSList *l;
608 for (l = tramp_infos; l; l = l->next) {
609 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
611 mono_tramp_info_free (info);
613 g_slist_free (tramp_infos);
616 /* Register trampolines created before the root domain was created in the jit info tables */
617 static void
618 register_trampolines (MonoDomain *domain)
620 GSList *l;
622 for (l = tramp_infos; l; l = l->next) {
623 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
625 register_trampoline_jit_info (domain, info);
629 G_GNUC_UNUSED static void
630 break_count (void)
635 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
636 * Set a breakpoint in break_count () to break the last time <x> is done.
638 G_GNUC_UNUSED gboolean
639 mono_debug_count (void)
641 static int count = 0, int_val = 0;
642 static gboolean inited, has_value = FALSE;
644 count ++;
646 if (!inited) {
647 char *value = g_getenv ("COUNT");
648 if (value) {
649 int_val = atoi (value);
650 g_free (value);
651 has_value = TRUE;
653 inited = TRUE;
656 if (!has_value)
657 return TRUE;
659 if (count == int_val)
660 break_count ();
662 if (count > int_val)
663 return FALSE;
665 return TRUE;
668 MonoMethod*
669 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
671 /* This icall is used to check for exceptions, so don't check in the wrapper */
672 gboolean check_exc = (callinfo != &mono_get_jit_icall_info ()->mono_thread_interruption_checkpoint);
674 return mono_marshal_get_icall_wrapper (callinfo, check_exc);
677 gconstpointer
678 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
680 ERROR_DECL (error);
681 MonoMethod *wrapper;
682 gconstpointer addr, trampoline;
683 MonoDomain *domain = mono_get_root_domain ();
685 if (callinfo->wrapper)
686 return callinfo->wrapper;
688 wrapper = mono_icall_get_wrapper_method (callinfo);
690 if (do_compile) {
691 addr = mono_compile_method_checked (wrapper, error);
692 mono_error_assert_ok (error);
693 mono_memory_barrier ();
694 callinfo->wrapper = addr;
695 return addr;
696 } else {
697 if (callinfo->trampoline)
698 return callinfo->trampoline;
699 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
700 mono_error_assert_ok (error);
701 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
703 mono_loader_lock ();
704 if (!callinfo->trampoline) {
705 callinfo->trampoline = trampoline;
707 mono_loader_unlock ();
709 return callinfo->trampoline;
713 gconstpointer
714 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
716 return mono_icall_get_wrapper_full (callinfo, FALSE);
719 static MonoJitDynamicMethodInfo*
720 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
722 MonoJitDynamicMethodInfo *res;
724 if (domain_jit_info (domain)->dynamic_code_hash)
725 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
726 else
727 res = NULL;
728 return res;
731 #ifdef __cplusplus
732 template <typename T>
733 static void
734 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, T func, const char *symbol, gboolean no_wrapper)
735 #else
736 static void
737 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, gpointer func, const char *symbol, gboolean no_wrapper)
738 #endif
740 #ifndef DISABLE_JIT
741 mini_register_opcode_emulation (opcode, jit_icall_info, name, sig, func, symbol, no_wrapper);
742 #else
743 // FIXME ifdef in mini_register_opcode_emulation and just call it.
745 g_assert (!sig->hasthis);
746 g_assert (sig->param_count < 3);
748 mono_register_jit_icall_info (jit_icall_info, func, name, sig, no_wrapper, symbol);
749 #endif
752 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
753 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
756 * For JIT icalls implemented in C.
757 * NAME should be the same as the name of the C function whose address is FUNC.
758 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
759 * can't throw exceptions.
761 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
762 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
764 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
765 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
766 * must be extern "C".
768 #define register_icall(func, sig, avoid_wrapper) \
769 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
771 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
772 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
775 * Register an icall where FUNC is dynamically generated or otherwise not
776 * possible to link to it using NAME during AOT.
778 * func is an expression, such a local variable or a function call to get a function pointer.
779 * name is an identifier
781 * Providing func and name separately is what distinguishes "dyn" from regular.
783 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
785 #define register_dyn_icall(func, name, sig, save) \
786 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
788 MonoLMF *
789 mono_get_lmf (void)
791 MonoJitTlsData *jit_tls;
793 if ((jit_tls = mono_tls_get_jit_tls ()))
794 return jit_tls->lmf;
796 * We do not assert here because this function can be called from
797 * mini-gc.c on a thread that has not executed any managed code, yet
798 * (the thread object allocation can trigger a collection).
800 return NULL;
803 void
804 mono_set_lmf (MonoLMF *lmf)
806 (*mono_get_lmf_addr ()) = lmf;
809 static void
810 mono_set_jit_tls (MonoJitTlsData *jit_tls)
812 MonoThreadInfo *info;
814 mono_tls_set_jit_tls (jit_tls);
816 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
817 info = mono_thread_info_current ();
818 if (info)
819 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
822 static void
823 mono_set_lmf_addr (MonoLMF **lmf_addr)
825 MonoThreadInfo *info;
827 mono_tls_set_lmf_addr (lmf_addr);
829 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
830 info = mono_thread_info_current ();
831 if (info)
832 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
836 * mono_push_lmf:
838 * Push an MonoLMFExt frame on the LMF stack.
840 void
841 mono_push_lmf (MonoLMFExt *ext)
843 MonoLMF **lmf_addr;
845 lmf_addr = mono_get_lmf_addr ();
847 ext->lmf.previous_lmf = *lmf_addr;
848 /* Mark that this is a MonoLMFExt */
849 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
851 mono_set_lmf ((MonoLMF*)ext);
855 * mono_pop_lmf:
857 * Pop the last frame from the LMF stack.
859 void
860 mono_pop_lmf (MonoLMF *lmf)
862 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
866 * mono_jit_thread_attach:
868 * Called by Xamarin.Mac and other products. Attach thread to runtime if
869 * needed and switch to @domain.
871 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
873 * If the thread is newly-attached, put into GC Safe mode.
875 * @return the original domain which needs to be restored, or NULL.
877 MonoDomain*
878 mono_jit_thread_attach (MonoDomain *domain)
880 MonoDomain *orig;
881 gboolean attached;
883 if (!domain) {
884 /* Happens when called from AOTed code which is only used in the root domain. */
885 domain = mono_get_root_domain ();
888 g_assert (domain);
890 attached = mono_tls_get_jit_tls () != NULL;
892 if (!attached) {
893 // #678164
894 gboolean background = TRUE;
895 mono_thread_attach_external_native_thread (domain, background);
897 /* mono_jit_thread_attach is external-only and not called by
898 * the runtime on any of our own threads. So if we get here,
899 * the thread is running native code - leave it in GC Safe mode
900 * and leave it to the n2m invoke wrappers or MONO_API entry
901 * points to switch to GC Unsafe.
903 MONO_STACKDATA (stackdata);
904 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
907 orig = mono_domain_get ();
908 if (orig != domain)
909 mono_domain_set_fast (domain, TRUE);
911 return orig != domain ? orig : NULL;
915 * mono_jit_set_domain:
917 * Set domain to @domain if @domain is not null
919 void
920 mono_jit_set_domain (MonoDomain *domain)
922 g_assert (!mono_threads_is_blocking_transition_enabled ());
924 if (domain)
925 mono_domain_set_fast (domain, TRUE);
929 * mono_thread_abort:
930 * \param obj exception object
931 * Abort the thread, print exception information and stack trace
933 static void
934 mono_thread_abort (MonoObject *obj)
936 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
938 /* handle_remove should be eventually called for this thread, too
939 g_free (jit_tls);*/
941 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
942 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
943 ((obj->vtable->klass) == mono_class_try_get_appdomain_unloaded_exception_class () &&
944 mono_thread_info_current ()->runtime_thread)) {
945 mono_thread_exit ();
946 } else {
947 mono_invoke_unhandled_exception_hook (obj);
951 static MonoJitTlsData*
952 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
954 MonoJitTlsData *jit_tls;
955 MonoLMF *lmf;
957 jit_tls = mono_tls_get_jit_tls ();
958 if (jit_tls)
959 return jit_tls;
961 jit_tls = g_new0 (MonoJitTlsData, 1);
963 jit_tls->abort_func = abort_func;
964 jit_tls->end_of_stack = stack_start;
966 mono_set_jit_tls (jit_tls);
968 lmf = g_new0 (MonoLMF, 1);
969 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
971 jit_tls->first_lmf = lmf;
973 mono_set_lmf_addr (&jit_tls->lmf);
975 jit_tls->lmf = lmf;
977 #ifdef MONO_ARCH_HAVE_TLS_INIT
978 mono_arch_tls_init ();
979 #endif
981 mono_setup_altstack (jit_tls);
983 return jit_tls;
986 static void
987 free_jit_tls_data (MonoJitTlsData *jit_tls)
989 //This happens during AOT cuz the thread is never attached
990 if (!jit_tls)
991 return;
992 mono_free_altstack (jit_tls);
994 if (jit_tls->interp_context)
995 mini_get_interp_callbacks ()->free_context (jit_tls->interp_context);
997 g_free (jit_tls->first_lmf);
998 g_free (jit_tls);
1001 static void
1002 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
1004 MonoThreadInfo *thread;
1005 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
1006 thread = mono_thread_info_current_unchecked ();
1007 if (thread)
1008 thread->jit_data = jit_tls;
1010 mono_arch_cpu_init ();
1013 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
1015 static void
1016 mono_thread_abort_dummy (MonoObject *obj)
1018 if (mono_thread_attach_aborted_cb)
1019 mono_thread_attach_aborted_cb (obj);
1020 else
1021 mono_thread_abort (obj);
1024 static void
1025 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
1027 MonoThreadInfo *thread;
1028 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
1029 thread = mono_thread_info_current_unchecked ();
1030 if (thread)
1031 thread->jit_data = jit_tls;
1033 mono_arch_cpu_init ();
1036 static void
1037 mini_thread_cleanup (MonoNativeThreadId tid)
1039 MonoJitTlsData *jit_tls = NULL;
1040 MonoThreadInfo *info;
1042 info = mono_thread_info_current_unchecked ();
1044 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1045 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1046 * not a trivial thing.
1048 * The current offender is mono_thread_manage which cleanup threads from the outside.
1050 if (info && mono_thread_info_get_tid (info) == tid) {
1051 jit_tls = info->jit_data;
1052 info->jit_data = NULL;
1054 mono_set_jit_tls (NULL);
1056 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1057 if (mono_get_lmf ()) {
1058 mono_set_lmf (NULL);
1059 mono_set_lmf_addr (NULL);
1061 } else {
1062 info = mono_thread_info_lookup (tid);
1063 if (info) {
1064 jit_tls = info->jit_data;
1065 info->jit_data = NULL;
1067 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1070 if (jit_tls)
1071 free_jit_tls_data (jit_tls);
1074 MonoJumpInfo *
1075 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1077 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1079 ji->ip.i = ip;
1080 ji->type = type;
1081 ji->data.target = target;
1082 ji->next = list;
1084 return ji;
1087 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1089 static const char* const patch_info_str[] = {
1090 #define PATCH_INFO(a,b) "" #a,
1091 #include "patch-info.h"
1092 #undef PATCH_INFO
1095 const char*
1096 mono_ji_type_to_string (MonoJumpInfoType type)
1098 return patch_info_str [type];
1101 void
1102 mono_print_ji (const MonoJumpInfo *ji)
1104 const char *type = patch_info_str [ji->type];
1105 switch (ji->type) {
1106 case MONO_PATCH_INFO_RGCTX_FETCH:
1107 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1108 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1110 printf ("[%s ", type);
1111 mono_print_ji (entry->data);
1112 printf (" -> %s]", mono_rgctx_info_type_to_str (entry->info_type));
1113 break;
1115 case MONO_PATCH_INFO_METHOD:
1116 case MONO_PATCH_INFO_METHODCONST:
1117 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1118 char *s = mono_method_get_full_name (ji->data.method);
1119 printf ("[%s %s]", type, s);
1120 g_free (s);
1121 break;
1123 case MONO_PATCH_INFO_JIT_ICALL_ID:
1124 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji->data.jit_icall_id)->name);
1125 break;
1126 case MONO_PATCH_INFO_CLASS:
1127 case MONO_PATCH_INFO_VTABLE: {
1128 char *name = mono_class_full_name (ji->data.klass);
1129 printf ("[%s %s]", type, name);
1130 g_free (name);
1131 break;
1133 default:
1134 printf ("[%s]", type);
1135 break;
1139 #else
1141 const char*
1142 mono_ji_type_to_string (MonoJumpInfoType type)
1144 return "";
1147 void
1148 mono_print_ji (const MonoJumpInfo *ji)
1152 #endif
1155 * mono_patch_info_dup_mp:
1157 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1159 MonoJumpInfo*
1160 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1162 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1163 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1165 switch (patch_info->type) {
1166 case MONO_PATCH_INFO_RVA:
1167 case MONO_PATCH_INFO_LDSTR:
1168 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1169 case MONO_PATCH_INFO_LDTOKEN:
1170 case MONO_PATCH_INFO_DECLSEC:
1171 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1172 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1173 break;
1174 case MONO_PATCH_INFO_SWITCH:
1175 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1176 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1177 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1178 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1179 break;
1180 case MONO_PATCH_INFO_RGCTX_FETCH:
1181 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1182 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1183 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1184 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1185 break;
1186 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1187 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1188 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1189 break;
1190 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1191 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1192 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1193 break;
1194 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1195 MonoGSharedVtMethodInfo *info;
1196 MonoGSharedVtMethodInfo *oinfo;
1197 int i;
1199 oinfo = patch_info->data.gsharedvt_method;
1200 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1201 res->data.gsharedvt_method = info;
1202 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1203 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1204 for (i = 0; i < oinfo->num_entries; ++i) {
1205 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1206 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1208 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1210 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1211 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1212 break;
1214 case MONO_PATCH_INFO_VIRT_METHOD: {
1215 MonoJumpInfoVirtMethod *info;
1216 MonoJumpInfoVirtMethod *oinfo;
1218 oinfo = patch_info->data.virt_method;
1219 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1220 res->data.virt_method = info;
1221 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1222 break;
1224 default:
1225 break;
1228 return res;
1231 guint
1232 mono_patch_info_hash (gconstpointer data)
1234 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1235 const MonoJumpInfoType type = ji->type;
1236 guint hash = type << 8;
1238 switch (type) {
1239 case MONO_PATCH_INFO_RVA:
1240 case MONO_PATCH_INFO_LDSTR:
1241 case MONO_PATCH_INFO_LDTOKEN:
1242 case MONO_PATCH_INFO_DECLSEC:
1243 return hash | ji->data.token->token;
1244 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1245 return hash | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1246 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: // Hash on the selector name
1247 case MONO_PATCH_INFO_LDSTR_LIT:
1248 return g_str_hash (ji->data.name);
1249 case MONO_PATCH_INFO_VTABLE:
1250 case MONO_PATCH_INFO_CLASS:
1251 case MONO_PATCH_INFO_IID:
1252 case MONO_PATCH_INFO_ADJUSTED_IID:
1253 case MONO_PATCH_INFO_METHODCONST:
1254 case MONO_PATCH_INFO_METHOD:
1255 case MONO_PATCH_INFO_METHOD_JUMP:
1256 case MONO_PATCH_INFO_METHOD_FTNDESC:
1257 case MONO_PATCH_INFO_IMAGE:
1258 case MONO_PATCH_INFO_ICALL_ADDR:
1259 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1260 case MONO_PATCH_INFO_FIELD:
1261 case MONO_PATCH_INFO_SFLDA:
1262 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1263 case MONO_PATCH_INFO_METHOD_RGCTX:
1264 case MONO_PATCH_INFO_SIGNATURE:
1265 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1266 case MONO_PATCH_INFO_AOT_JIT_INFO:
1267 case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE:
1268 return hash | (gssize)ji->data.target;
1269 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1270 return hash | (gssize)ji->data.gsharedvt->method;
1271 case MONO_PATCH_INFO_RGCTX_FETCH:
1272 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1273 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1274 hash |= e->in_mrgctx | e->info_type | mono_patch_info_hash (e->data);
1275 if (e->in_mrgctx)
1276 return hash | (gssize)e->d.method;
1277 else
1278 return hash | (gssize)e->d.klass;
1280 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1281 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1282 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1283 case MONO_PATCH_INFO_GC_NURSERY_START:
1284 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1285 case MONO_PATCH_INFO_GOT_OFFSET:
1286 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1287 case MONO_PATCH_INFO_AOT_MODULE:
1288 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1289 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1290 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES:
1291 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE:
1292 return hash;
1293 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1294 return hash | ji->data.uindex;
1295 case MONO_PATCH_INFO_JIT_ICALL_ID:
1296 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1297 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1298 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1299 return hash | ji->data.index;
1300 case MONO_PATCH_INFO_SWITCH:
1301 return hash | ji->data.table->table_size;
1302 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1303 return hash | (gssize)ji->data.gsharedvt_method->method;
1304 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1305 return hash | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1306 case MONO_PATCH_INFO_VIRT_METHOD: {
1307 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1309 return hash | (gssize)info->klass | (gssize)info->method;
1311 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1312 return hash | mono_signature_hash (ji->data.sig);
1313 case MONO_PATCH_INFO_R8_GOT:
1314 return hash | (guint32)*(double*)ji->data.target;
1315 case MONO_PATCH_INFO_R4_GOT:
1316 return hash | (guint32)*(float*)ji->data.target;
1317 default:
1318 printf ("info type: %d\n", ji->type);
1319 mono_print_ji (ji); printf ("\n");
1320 g_assert_not_reached ();
1321 case MONO_PATCH_INFO_NONE:
1322 return 0;
1327 * mono_patch_info_equal:
1329 * This might fail to recognize equivalent patches, i.e. floats, so its only
1330 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1331 * in AOT.
1333 gint
1334 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1336 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1337 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1339 MonoJumpInfoType const ji1_type = ji1->type;
1340 MonoJumpInfoType const ji2_type = ji2->type;
1342 if (ji1_type != ji2_type)
1343 return 0;
1345 switch (ji1_type) {
1346 case MONO_PATCH_INFO_RVA:
1347 case MONO_PATCH_INFO_LDSTR:
1348 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1349 case MONO_PATCH_INFO_LDTOKEN:
1350 case MONO_PATCH_INFO_DECLSEC:
1351 return ji1->data.token->image == ji2->data.token->image &&
1352 ji1->data.token->token == ji2->data.token->token &&
1353 ji1->data.token->has_context == ji2->data.token->has_context &&
1354 ji1->data.token->context.class_inst == ji2->data.token->context.class_inst &&
1355 ji1->data.token->context.method_inst == ji2->data.token->context.method_inst;
1356 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1357 case MONO_PATCH_INFO_LDSTR_LIT:
1358 return g_str_equal (ji1->data.name, ji2->data.name);
1359 case MONO_PATCH_INFO_RGCTX_FETCH:
1360 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1361 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1362 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1364 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);
1366 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1367 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1368 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1370 return c1->sig == c2->sig && c1->method == c2->method;
1372 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1373 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1374 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1375 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;
1376 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1377 return ji1->data.uindex == ji2->data.uindex;
1378 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1379 return ji1->data.index == ji2->data.index;
1380 case MONO_PATCH_INFO_JIT_ICALL_ID:
1381 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1382 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1383 return ji1->data.jit_icall_id == ji2->data.jit_icall_id;
1384 case MONO_PATCH_INFO_VIRT_METHOD:
1385 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1386 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1387 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig);
1388 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1389 case MONO_PATCH_INFO_NONE:
1390 return 1;
1391 default:
1392 break;
1395 return ji1->data.target == ji2->data.target;
1398 gpointer
1399 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1401 unsigned char *ip = patch_info->ip.i + code;
1402 gconstpointer target = NULL;
1404 error_init (error);
1406 switch (patch_info->type) {
1407 case MONO_PATCH_INFO_BB:
1409 * FIXME: This could be hit for methods without a prolog. Should use -1
1410 * but too much code depends on a 0 initial value.
1412 //g_assert (patch_info->data.bb->native_offset);
1413 target = patch_info->data.bb->native_offset + code;
1414 break;
1415 case MONO_PATCH_INFO_ABS:
1416 target = patch_info->data.target;
1417 break;
1418 case MONO_PATCH_INFO_LABEL:
1419 target = patch_info->data.inst->inst_c0 + code;
1420 break;
1421 case MONO_PATCH_INFO_IP:
1422 target = ip;
1423 break;
1424 case MONO_PATCH_INFO_JIT_ICALL_ID: {
1425 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1426 target = mono_icall_get_wrapper (mi);
1427 break;
1429 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1430 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1431 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1432 target = mi->func;
1433 break;
1435 case MONO_PATCH_INFO_METHOD_JUMP:
1436 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1437 if (!is_ok (error))
1438 return NULL;
1439 break;
1440 case MONO_PATCH_INFO_METHOD:
1441 if (patch_info->data.method == method) {
1442 target = code;
1443 } else {
1444 /* get the trampoline to the method from the domain */
1445 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1446 if (!is_ok (error))
1447 return NULL;
1449 break;
1450 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1452 * Return an ftndesc for either AOTed code, or for an interp entry.
1454 target = mini_llvmonly_load_method_ftndesc (patch_info->data.method, FALSE, FALSE, error);
1455 return_val_if_nok (error, NULL);
1456 break;
1458 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1459 gpointer code_slot;
1461 mono_domain_lock (domain);
1462 if (!domain_jit_info (domain)->method_code_hash)
1463 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1464 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1465 if (!code_slot) {
1466 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1467 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1469 mono_domain_unlock (domain);
1470 target = code_slot;
1471 break;
1473 case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE: {
1474 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1475 break;
1477 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1478 target = (gpointer)&mono_polling_required;
1479 break;
1480 case MONO_PATCH_INFO_SWITCH: {
1481 #ifndef MONO_ARCH_NO_CODEMAN
1482 gpointer *jump_table;
1483 int i;
1485 if (method && method->dynamic) {
1486 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1487 } else {
1488 MonoMemoryManager *mem_manager = m_method_get_mem_manager (domain, method);
1489 if (mono_aot_only) {
1490 jump_table = (void **)mono_mem_manager_alloc (mem_manager, sizeof (gpointer) * patch_info->data.table->table_size);
1491 } else {
1492 jump_table = (void **)mono_mem_manager_code_reserve (mem_manager, sizeof (gpointer) * patch_info->data.table->table_size);
1496 mono_codeman_enable_write ();
1497 for (i = 0; i < patch_info->data.table->table_size; i++) {
1498 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1500 mono_codeman_disable_write ();
1502 target = jump_table;
1503 #else
1504 g_assert_not_reached ();
1505 target = NULL;
1506 #endif
1507 break;
1509 case MONO_PATCH_INFO_METHODCONST:
1510 case MONO_PATCH_INFO_CLASS:
1511 case MONO_PATCH_INFO_IMAGE:
1512 case MONO_PATCH_INFO_FIELD:
1513 case MONO_PATCH_INFO_SIGNATURE:
1514 case MONO_PATCH_INFO_AOT_MODULE:
1515 target = patch_info->data.target;
1516 break;
1517 case MONO_PATCH_INFO_IID:
1518 mono_class_init_internal (patch_info->data.klass);
1519 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1520 break;
1521 case MONO_PATCH_INFO_ADJUSTED_IID:
1522 mono_class_init_internal (patch_info->data.klass);
1523 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1524 break;
1525 case MONO_PATCH_INFO_VTABLE:
1526 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1527 mono_error_assert_ok (error);
1528 break;
1529 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1530 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1532 if (del_tramp->is_virtual)
1533 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1534 else
1535 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1536 break;
1538 case MONO_PATCH_INFO_SFLDA: {
1539 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1540 mono_error_assert_ok (error);
1542 if (mono_class_field_is_special_static (patch_info->data.field)) {
1543 gpointer addr = NULL;
1545 mono_domain_lock (domain);
1546 if (domain->special_static_fields)
1547 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1548 mono_domain_unlock (domain);
1549 g_assert (addr);
1550 return addr;
1553 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (!method || mono_class_needs_cctor_run (vtable->klass, method)))
1554 /* Done by the generated code */
1556 else {
1557 if (run_cctors) {
1558 if (!mono_runtime_class_init_full (vtable, error)) {
1559 return NULL;
1563 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1564 break;
1566 case MONO_PATCH_INFO_RVA: {
1567 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1568 guint32 rva;
1570 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1571 target = mono_image_rva_map (patch_info->data.token->image, rva);
1572 break;
1574 case MONO_PATCH_INFO_R4:
1575 case MONO_PATCH_INFO_R4_GOT:
1576 case MONO_PATCH_INFO_R8:
1577 case MONO_PATCH_INFO_R8_GOT:
1578 target = patch_info->data.target;
1579 break;
1580 case MONO_PATCH_INFO_EXC_NAME:
1581 target = patch_info->data.name;
1582 break;
1583 case MONO_PATCH_INFO_LDSTR:
1584 target =
1585 mono_ldstr_checked (domain, patch_info->data.token->image,
1586 mono_metadata_token_index (patch_info->data.token->token), error);
1587 break;
1588 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1589 gpointer handle;
1590 MonoClass *handle_class;
1592 handle = mono_ldtoken_checked (patch_info->data.token->image,
1593 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1594 if (!is_ok (error))
1595 return NULL;
1596 mono_class_init_internal (handle_class);
1597 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType *)handle));
1599 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1600 if (!is_ok (error))
1601 return NULL;
1602 break;
1604 case MONO_PATCH_INFO_LDTOKEN: {
1605 gpointer handle;
1606 MonoClass *handle_class;
1608 handle = mono_ldtoken_checked (patch_info->data.token->image,
1609 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1610 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1611 mono_class_init_internal (handle_class);
1613 target = handle;
1614 break;
1616 case MONO_PATCH_INFO_DECLSEC:
1617 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1618 break;
1619 case MONO_PATCH_INFO_ICALL_ADDR:
1620 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1621 /* run_cctors == 0 -> AOT */
1622 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1623 if (run_cctors) {
1624 target = mono_lookup_pinvoke_call_internal (patch_info->data.method, error);
1625 if (!target) {
1626 if (mono_aot_only)
1627 return NULL;
1628 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));
1630 } else {
1631 target = NULL;
1633 } else {
1634 target = mono_lookup_internal_call (patch_info->data.method);
1636 if (mono_is_missing_icall_addr (target) && run_cctors)
1637 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1639 break;
1640 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1641 target = &mono_thread_interruption_request_flag;
1642 break;
1643 case MONO_PATCH_INFO_METHOD_RGCTX:
1644 target = mini_method_get_rgctx (patch_info->data.method);
1645 break;
1646 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1647 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1649 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1650 break;
1652 case MONO_PATCH_INFO_BB_OVF:
1653 case MONO_PATCH_INFO_EXC_OVF:
1654 case MONO_PATCH_INFO_GOT_OFFSET:
1655 case MONO_PATCH_INFO_NONE:
1656 break;
1657 case MONO_PATCH_INFO_RGCTX_FETCH: {
1658 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1660 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1661 break;
1663 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1664 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1665 if (!run_cctors)
1666 /* AOT, not needed */
1667 target = NULL;
1668 else
1669 target = mono_arch_get_seq_point_info (domain, code);
1670 break;
1671 #endif
1672 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1673 int card_table_shift_bits;
1674 gpointer card_table_mask;
1676 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1677 break;
1679 case MONO_PATCH_INFO_GC_NURSERY_START: {
1680 int shift_bits;
1681 size_t size;
1683 target = mono_gc_get_nursery (&shift_bits, &size);
1684 break;
1686 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1687 int shift_bits;
1688 size_t size;
1690 mono_gc_get_nursery (&shift_bits, &size);
1692 target = (gpointer)(gssize)shift_bits;
1693 break;
1695 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1696 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1697 break;
1699 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1700 target = NULL;
1701 break;
1703 case MONO_PATCH_INFO_LDSTR_LIT: {
1704 int len;
1705 char *s;
1707 len = strlen ((const char *)patch_info->data.target);
1708 s = (char *)mono_domain_alloc0 (domain, len + 1);
1709 memcpy (s, patch_info->data.target, len);
1710 target = s;
1712 break;
1714 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1715 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1716 break;
1717 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1718 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1719 break;
1721 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1722 target = (gpointer) &mono_profiler_state.exception_clause_count;
1723 break;
1725 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES:
1726 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE: {
1727 /* Resolved in aot-runtime.c */
1728 g_assert_not_reached ();
1729 target = NULL;
1730 break;
1732 default:
1733 g_assert_not_reached ();
1736 return (gpointer)target;
1740 * mini_register_jump_site:
1742 * Register IP as a jump/tailcall site which calls METHOD.
1743 * This is needed because common_call_trampoline () cannot patch
1744 * the call site because the caller ip is not available for jumps.
1746 void
1747 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1749 MonoJumpList *jlist;
1751 MonoMethod *shared_method = mini_method_to_shared (method);
1752 method = shared_method ? shared_method : method;
1754 mono_domain_lock (domain);
1755 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1756 if (!jlist) {
1757 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1758 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1760 jlist->list = g_slist_prepend (jlist->list, ip);
1761 mono_domain_unlock (domain);
1765 * mini_patch_jump_sites:
1767 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1769 void
1770 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1772 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1774 if (!hash)
1775 return;
1777 MonoJumpInfo patch_info;
1778 MonoJumpList *jlist;
1779 GSList *tmp;
1781 /* The caller/callee might use different instantiations */
1782 MonoMethod *shared_method = mini_method_to_shared (method);
1783 method = shared_method ? shared_method : method;
1785 mono_domain_lock (domain);
1786 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1787 if (jlist)
1788 g_hash_table_remove (hash, method);
1789 mono_domain_unlock (domain);
1790 if (jlist) {
1791 patch_info.next = NULL;
1792 patch_info.ip.i = 0;
1793 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1794 patch_info.data.method = method;
1796 mono_codeman_enable_write ();
1798 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1799 for (tmp = jlist->list; tmp; tmp = tmp->next)
1800 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1801 #else
1802 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1803 // for gshared methods
1804 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1805 ERROR_DECL (error);
1806 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1807 mono_error_assert_ok (error);
1809 #endif
1811 mono_codeman_disable_write ();
1816 * mini_patch_llvm_jit_callees:
1818 * Patch function address slots used by llvm JITed code.
1820 void
1821 mini_patch_llvm_jit_callees (MonoDomain *domain, MonoMethod *method, gpointer addr)
1823 if (!domain_jit_info (domain)->llvm_jit_callees)
1824 return;
1825 GSList *callees = (GSList*)g_hash_table_lookup (domain_jit_info (domain)->llvm_jit_callees, method);
1826 GSList *l;
1828 for (l = callees; l; l = l->next) {
1829 gpointer *slot = (gpointer*)l->data;
1831 *slot = addr;
1835 void
1836 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1838 MonoGenericInst *inst;
1839 int i;
1841 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1843 if (context && context->class_inst) {
1844 inst = context->class_inst;
1845 for (i = 0; i < inst->type_argc; ++i) {
1846 MonoType *type = inst->type_argv [i];
1848 if (mini_is_gsharedvt_gparam (type))
1849 gsctx->is_gsharedvt = TRUE;
1852 if (context && context->method_inst) {
1853 inst = context->method_inst;
1855 for (i = 0; i < inst->type_argc; ++i) {
1856 MonoType *type = inst->type_argv [i];
1858 if (mini_is_gsharedvt_gparam (type))
1859 gsctx->is_gsharedvt = TRUE;
1865 * LOCKING: Acquires the jit code hash lock.
1867 MonoJitInfo*
1868 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1870 MonoJitInfo *ji;
1871 static gboolean inited = FALSE;
1872 static int lookups = 0;
1873 static int failed_lookups = 0;
1875 mono_domain_jit_code_hash_lock (domain);
1876 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1877 if (!ji && shared) {
1878 /* Try generic sharing */
1879 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1880 if (ji && !ji->has_generic_jit_info)
1881 ji = NULL;
1882 if (!inited) {
1883 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1884 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1885 inited = TRUE;
1888 ++lookups;
1889 if (!ji)
1890 ++failed_lookups;
1892 mono_domain_jit_code_hash_unlock (domain);
1894 return ji;
1897 static MonoJitInfo*
1898 lookup_method (MonoDomain *domain, MonoMethod *method)
1900 ERROR_DECL (error);
1901 MonoJitInfo *ji;
1902 MonoMethod *shared;
1904 ji = mini_lookup_method (domain, method, NULL);
1906 if (!ji) {
1907 if (!mono_method_is_generic_sharable (method, FALSE))
1908 return NULL;
1909 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1910 mono_error_assert_ok (error);
1911 ji = mini_lookup_method (domain, method, shared);
1914 return ji;
1917 MonoClass*
1918 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1920 ERROR_DECL (error);
1921 MonoClass *klass;
1923 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1924 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1925 if (context) {
1926 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1927 mono_error_cleanup (error); /* FIXME don't swallow the error */
1929 } else {
1930 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1931 mono_error_cleanup (error); /* FIXME don't swallow the error */
1933 if (klass)
1934 mono_class_init_internal (klass);
1935 return klass;
1938 #if ENABLE_JIT_MAP
1939 static FILE* perf_map_file;
1941 void
1942 mono_enable_jit_map (void)
1944 if (!perf_map_file) {
1945 char name [64];
1946 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1947 unlink (name);
1948 perf_map_file = fopen (name, "w");
1952 void
1953 mono_emit_jit_tramp (void *start, int size, const char *desc)
1955 if (perf_map_file)
1956 fprintf (perf_map_file, "%" PRIx64 " %x %s\n", (guint64)(gsize)start, size, desc);
1959 void
1960 mono_emit_jit_map (MonoJitInfo *jinfo)
1962 if (perf_map_file) {
1963 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1964 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1965 g_free (name);
1969 gboolean
1970 mono_jit_map_is_enabled (void)
1972 return perf_map_file != NULL;
1975 #endif
1977 #ifdef ENABLE_JIT_DUMP
1978 #include <sys/mman.h>
1979 #include <sys/syscall.h>
1980 #include <elf.h>
1982 static FILE *perf_dump_file;
1983 static mono_mutex_t perf_dump_mutex;
1984 static void *perf_dump_mmap_addr = MAP_FAILED;
1985 static guint32 perf_dump_pid;
1986 static clockid_t clock_id = CLOCK_MONOTONIC;
1988 enum {
1989 JIT_DUMP_MAGIC = 0x4A695444,
1990 JIT_DUMP_VERSION = 2,
1991 #if HOST_X86
1992 ELF_MACHINE = EM_386,
1993 #elif HOST_AMD64
1994 ELF_MACHINE = EM_X86_64,
1995 #elif HOST_ARM
1996 ELF_MACHINE = EM_ARM,
1997 #elif HOST_ARM64
1998 ELF_MACHINE = EM_AARCH64,
1999 #elif HOST_POWERPC64
2000 ELF_MACHINE = EM_PPC64,
2001 #elif HOST_S390X
2002 ELF_MACHINE = EM_S390,
2003 #elif HOST_RISCV
2004 ELF_MACHINE = EM_RISCV,
2005 #elif HOST_MIPS
2006 ELF_MACHINE = EM_MIPS,
2007 #elif HOST_LOONGARCH64
2008 ELF_MACHINE = EM_LOONGARCH,
2009 #endif
2010 JIT_CODE_LOAD = 0
2012 typedef struct
2014 guint32 magic;
2015 guint32 version;
2016 guint32 total_size;
2017 guint32 elf_mach;
2018 guint32 pad1;
2019 guint32 pid;
2020 guint64 timestamp;
2021 guint64 flags;
2022 } FileHeader;
2023 typedef struct
2025 guint32 id;
2026 guint32 total_size;
2027 guint64 timestamp;
2028 } RecordHeader;
2029 typedef struct
2031 RecordHeader header;
2032 guint32 pid;
2033 guint32 tid;
2034 guint64 vma;
2035 guint64 code_addr;
2036 guint64 code_size;
2037 guint64 code_index;
2038 // Null terminated function name
2039 // Native code
2040 } JitCodeLoadRecord;
2042 static void add_file_header_info (FileHeader *header);
2043 static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record);
2045 void
2046 mono_enable_jit_dump (void)
2048 if (perf_dump_pid == 0)
2049 perf_dump_pid = getpid();
2051 if (!perf_dump_file) {
2052 char name [64];
2053 FileHeader header;
2054 memset (&header, 0, sizeof (header));
2056 mono_os_mutex_init (&perf_dump_mutex);
2057 mono_os_mutex_lock (&perf_dump_mutex);
2059 g_snprintf (name, sizeof (name), "/tmp/jit-%d.dump", perf_dump_pid);
2060 unlink (name);
2061 perf_dump_file = fopen (name, "w");
2063 add_file_header_info (&header);
2064 if (perf_dump_file) {
2065 fwrite (&header, sizeof (header), 1, perf_dump_file);
2066 //This informs perf of the presence of the jitdump file and support for the feature.
2067 perf_dump_mmap_addr = mmap (NULL, sizeof (header), PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno (perf_dump_file), 0);
2070 mono_os_mutex_unlock (&perf_dump_mutex);
2074 static void
2075 add_file_header_info (FileHeader *header)
2077 header->magic = JIT_DUMP_MAGIC;
2078 header->version = JIT_DUMP_VERSION;
2079 header->total_size = sizeof (header);
2080 header->elf_mach = ELF_MACHINE;
2081 header->pad1 = 0;
2082 header->pid = perf_dump_pid;
2083 header->timestamp = mono_clock_get_time_ns (clock_id);
2084 header->flags = 0;
2087 void
2088 mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2090 static uint64_t code_index;
2092 if (perf_dump_file) {
2093 JitCodeLoadRecord record;
2094 size_t nameLen = strlen (jinfo->d.method->name);
2095 memset (&record, 0, sizeof (record));
2097 add_basic_JitCodeLoadRecord_info (&record);
2098 record.header.total_size = sizeof (record) + nameLen + 1 + jinfo->code_size;
2099 record.vma = (guint64)jinfo->code_start;
2100 record.code_addr = (guint64)jinfo->code_start;
2101 record.code_size = (guint64)jinfo->code_size;
2103 mono_os_mutex_lock (&perf_dump_mutex);
2105 record.code_index = ++code_index;
2107 // TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held).
2109 record.header.timestamp = mono_clock_get_time_ns (clock_id);
2111 fwrite (&record, sizeof (record), 1, perf_dump_file);
2112 fwrite (jinfo->d.method->name, nameLen + 1, 1, perf_dump_file);
2113 fwrite (code, jinfo->code_size, 1, perf_dump_file);
2115 mono_os_mutex_unlock (&perf_dump_mutex);
2119 static void
2120 add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record)
2122 record->header.id = JIT_CODE_LOAD;
2123 record->header.timestamp = mono_clock_get_time_ns (clock_id);
2124 record->pid = perf_dump_pid;
2125 record->tid = syscall (SYS_gettid);
2128 void
2129 mono_jit_dump_cleanup (void)
2131 if (perf_dump_mmap_addr != MAP_FAILED)
2132 munmap (perf_dump_mmap_addr, sizeof(FileHeader));
2133 if (perf_dump_file)
2134 fclose (perf_dump_file);
2137 #else
2139 void
2140 mono_enable_jit_dump (void)
2144 void
2145 mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2149 void
2150 mono_jit_dump_cleanup (void)
2154 #endif
2156 static void
2157 no_gsharedvt_in_wrapper (void)
2159 g_assert_not_reached ();
2163 Overall algorithm:
2165 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.
2166 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
2167 Dependency management in this case is too complex to justify implementing it.
2169 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
2171 TODO:
2172 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
2173 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
2174 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
2175 Maybe pool JitCompilationEntry, specially those with an inited cond var;
2177 typedef struct {
2178 MonoMethod *method;
2179 MonoDomain *domain;
2180 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
2181 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
2182 int threads_waiting; /* Number of threads waiting on this job */
2183 gboolean has_cond; /* True if @cond was initialized */
2184 gboolean done; /* True if the method finished JIT'ing */
2185 MonoCoopCond cond; /* Cond sleeping threads wait one */
2186 } JitCompilationEntry;
2188 typedef struct {
2189 GPtrArray *in_flight_methods; //JitCompilationEntry*
2190 MonoCoopMutex lock;
2191 } JitCompilationData;
2194 Timeout, in millisecounds, that we wait other threads to finish JITing.
2195 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.
2197 #define MAX_JIT_TIMEOUT_MS 1000
2200 static JitCompilationData compilation_data;
2201 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
2203 static void
2204 mini_jit_init_job_control (void)
2206 mono_coop_mutex_init (&compilation_data.lock);
2207 compilation_data.in_flight_methods = g_ptr_array_new ();
2210 static void
2211 lock_compilation_data (void)
2213 mono_coop_mutex_lock (&compilation_data.lock);
2216 static void
2217 unlock_compilation_data (void)
2219 mono_coop_mutex_unlock (&compilation_data.lock);
2222 static JitCompilationEntry*
2223 find_method (MonoMethod *method, MonoDomain *domain)
2225 int i;
2226 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
2227 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
2228 if (e->method == method && e->domain == domain)
2229 return e;
2232 return NULL;
2235 static void
2236 add_current_thread (MonoJitTlsData *jit_tls)
2238 ++jit_tls->active_jit_methods;
2241 static void
2242 unref_jit_entry (JitCompilationEntry *entry)
2244 --entry->ref_count;
2245 if (entry->ref_count)
2246 return;
2247 if (entry->has_cond)
2248 mono_coop_cond_destroy (&entry->cond);
2249 g_free (entry);
2253 * Returns true if this method waited successfully for another thread to JIT it
2255 static gboolean
2256 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2258 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2259 JitCompilationEntry *entry;
2261 static gboolean inited;
2262 if (!inited) {
2263 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2264 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2265 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2266 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2267 inited = TRUE;
2270 lock_compilation_data ();
2272 if (!(entry = find_method (method, domain))) {
2273 entry = g_new0 (JitCompilationEntry, 1);
2274 entry->method = method;
2275 entry->domain = domain;
2276 entry->compilation_count = entry->ref_count = 1;
2277 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2278 g_assert (find_method (method, domain) == entry);
2279 add_current_thread (jit_tls);
2281 unlock_compilation_data ();
2282 return FALSE;
2283 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2284 //We can't suspend the current thread if it's already JITing a method.
2285 //Dependency management is too compilated and we want to get rid of this anyways.
2287 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2288 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2290 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2291 ++entry->compilation_count;
2292 ++jit_methods_multiple;
2293 ++jit_tls->active_jit_methods;
2295 unlock_compilation_data ();
2296 return FALSE;
2297 } else {
2298 ++jit_methods_waited;
2299 ++entry->ref_count;
2301 if (!entry->has_cond) {
2302 mono_coop_cond_init (&entry->cond);
2303 entry->has_cond = TRUE;
2306 while (TRUE) {
2307 ++entry->threads_waiting;
2309 g_assert (entry->has_cond);
2310 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2311 --entry->threads_waiting;
2313 if (entry->done) {
2314 unref_jit_entry (entry);
2315 unlock_compilation_data ();
2316 return TRUE;
2317 } else {
2318 //We hit the timeout or a spurious wakeup, fallback to JITing
2319 g_assert (entry->ref_count > 1);
2320 unref_jit_entry (entry);
2321 ++jit_spurious_wakeups_or_timeouts;
2323 ++entry->compilation_count;
2324 ++jit_methods_multiple;
2325 ++jit_tls->active_jit_methods;
2327 unlock_compilation_data ();
2328 return FALSE;
2334 static void
2335 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2337 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2339 lock_compilation_data ();
2341 g_assert (jit_tls->active_jit_methods > 0);
2342 --jit_tls->active_jit_methods;
2344 JitCompilationEntry *entry = find_method (method, target_domain);
2345 g_assert (entry); // It would be weird to fail
2346 entry->done = TRUE;
2348 if (entry->threads_waiting) {
2349 g_assert (entry->has_cond);
2350 mono_coop_cond_broadcast (&entry->cond);
2353 if (--entry->compilation_count == 0) {
2354 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2355 unref_jit_entry (entry);
2358 unlock_compilation_data ();
2361 static MonoJitInfo*
2362 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2364 MonoDomain *domain = mono_get_root_domain ();
2365 MonoJitInfo *jinfo;
2366 guint8 *uw_info;
2367 guint32 info_len;
2369 if (info->uw_info) {
2370 uw_info = info->uw_info;
2371 info_len = info->uw_info_len;
2372 } else {
2373 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2376 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2377 jinfo->d.method = wrapper;
2378 jinfo->code_start = MINI_FTNPTR_TO_ADDR (info->code);
2379 jinfo->code_size = info->code_size;
2380 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2382 if (!info->uw_info)
2383 g_free (uw_info);
2385 return jinfo;
2388 static gpointer
2389 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2391 MonoJitInfo *jinfo;
2392 gpointer code;
2394 if (mono_llvm_only) {
2395 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2396 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2398 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2400 * These wrappers are only created for signatures which are in the program, but
2401 * sometimes we load methods too eagerly and have to create them even if they
2402 * will never be called.
2404 return (gpointer)no_gsharedvt_in_wrapper;
2409 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2410 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2411 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2413 if (!piinfo->addr) {
2414 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2415 guint32 flags = MONO_ICALL_FLAGS_NONE;
2416 gpointer icall_addr;
2417 icall_addr = (gpointer)mono_lookup_internal_call_full_with_flags (method, TRUE, (guint32 *)&flags);
2418 if (flags & MONO_ICALL_FLAGS_NO_WRAPPER) {
2419 piinfo->icflags = MONO_ICALL_FLAGS_NO_WRAPPER;
2420 mono_memory_write_barrier ();
2422 piinfo->addr = icall_addr;
2423 } else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE) {
2424 #ifdef HOST_WIN32
2425 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);
2426 #else
2427 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);
2428 #endif
2429 } else {
2430 ERROR_DECL (ignored_error);
2431 mono_lookup_pinvoke_call_internal (method, ignored_error);
2432 mono_error_cleanup (ignored_error);
2436 mono_memory_read_barrier ();
2438 gpointer compiled_method = NULL;
2439 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && (piinfo->icflags & MONO_ICALL_FLAGS_NO_WRAPPER)) {
2440 compiled_method = piinfo->addr;
2441 } else {
2442 MonoMethod *nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2443 compiled_method = mono_jit_compile_method_jit_only (nm, error);
2444 return_val_if_nok (error, NULL);
2447 code = mono_get_addr_from_ftnptr (compiled_method);
2448 jinfo = mono_jit_info_table_find (target_domain, code);
2449 if (!jinfo)
2450 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2451 if (jinfo)
2452 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2453 return code;
2454 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2455 const char *name = method->name;
2456 char *full_name;
2457 MonoMethod *nm;
2459 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2460 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2461 MonoJitICallInfo *mi = &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor;
2463 * We need to make sure this wrapper
2464 * is compiled because it might end up
2465 * in an (M)RGCTX if generic sharing
2466 * is enabled, and would be called
2467 * indirectly. If it were a
2468 * trampoline we'd try to patch that
2469 * indirect call, which is not
2470 * possible.
2472 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2473 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2474 if (mono_llvm_only) {
2475 nm = mono_marshal_get_delegate_invoke (method, NULL);
2476 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2477 return_val_if_nok (error, NULL);
2478 return mono_get_addr_from_ftnptr (compiled_ptr);
2481 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2482 if (mono_use_interpreter)
2483 return NULL;
2485 return mono_create_delegate_trampoline (target_domain, method->klass);
2486 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2487 nm = mono_marshal_get_delegate_begin_invoke (method);
2488 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2489 return_val_if_nok (error, NULL);
2490 return mono_get_addr_from_ftnptr (compiled_ptr);
2491 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2492 nm = mono_marshal_get_delegate_end_invoke (method);
2493 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2494 return_val_if_nok (error, NULL);
2495 return mono_get_addr_from_ftnptr (compiled_ptr);
2499 full_name = mono_method_full_name (method, TRUE);
2500 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2501 g_free (full_name);
2502 return NULL;
2505 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2506 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2508 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2509 static MonoTrampInfo *in_tinfo, *out_tinfo;
2510 MonoTrampInfo *tinfo;
2511 MonoJitInfo *jinfo;
2512 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2514 if (is_in && in_tinfo)
2515 return in_tinfo->code;
2516 else if (!is_in && out_tinfo)
2517 return out_tinfo->code;
2520 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2521 * works.
2522 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2524 if (mono_ee_features.use_aot_trampolines)
2525 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2526 else
2527 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2528 jinfo = create_jit_info_for_trampoline (method, tinfo);
2529 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2530 if (is_in)
2531 in_tinfo = tinfo;
2532 else
2533 out_tinfo = tinfo;
2534 return tinfo->code;
2538 return NULL;
2541 static gpointer
2542 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2544 MonoDomain *target_domain, *domain = mono_domain_get ();
2545 MonoJitInfo *info;
2546 gpointer code = NULL, p;
2547 MonoJitICallInfo *callinfo = NULL;
2548 WrapperInfo *winfo = NULL;
2549 gboolean use_interp = FALSE;
2551 error_init (error);
2553 if (mono_ee_features.force_use_interpreter && !jit_only)
2554 use_interp = TRUE;
2555 if (!use_interp && mono_interp_only_classes) {
2556 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2557 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2558 use_interp = TRUE;
2561 if (use_interp) {
2562 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2563 if (code)
2564 return code;
2567 if (mono_llvm_only)
2568 /* Should be handled by the caller */
2569 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2572 * ICALL wrappers are handled specially, since there is only one copy of them
2573 * shared by all appdomains.
2575 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2576 winfo = mono_marshal_get_wrapper_info (method);
2577 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2578 callinfo = mono_find_jit_icall_info (winfo->d.icall.jit_icall_id);
2580 /* Must be domain neutral since there is only one copy */
2581 opt |= MONO_OPT_SHARED;
2582 } else {
2583 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2584 opt &= ~MONO_OPT_SHARED;
2587 if (opt & MONO_OPT_SHARED)
2588 target_domain = mono_get_root_domain ();
2589 else
2590 target_domain = domain;
2592 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2593 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2595 g_assert (info);
2596 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2597 MonoGenericContext *ctx = NULL;
2598 if (method->is_inflated)
2599 ctx = mono_method_get_context (method);
2600 method = info->d.synchronized_inner.method;
2601 if (ctx) {
2602 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2603 g_assert (is_ok (error)); /* FIXME don't swallow the error */
2608 lookup_start:
2609 info = lookup_method (target_domain, method);
2610 if (info) {
2611 /* We can't use a domain specific method in another domain */
2612 if (! ((domain != target_domain) && !info->domain_neutral)) {
2613 MonoVTable *vtable;
2615 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2616 vtable = mono_class_vtable_checked (domain, method->klass, error);
2617 if (!is_ok (error))
2618 return NULL;
2619 g_assert (vtable);
2620 if (!mono_runtime_class_init_full (vtable, error))
2621 return NULL;
2623 code = MINI_ADDR_TO_FTNPTR (info->code_start);
2624 return mono_create_ftnptr (target_domain, code);
2628 #ifdef MONO_USE_AOT_COMPILER
2629 if (opt & MONO_OPT_AOT) {
2630 MonoDomain *domain = NULL;
2632 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2633 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2634 g_assert (info);
2635 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2636 /* AOT'd wrappers for interp must be owned by root domain */
2637 domain = mono_get_root_domain ();
2640 if (!domain)
2641 domain = mono_domain_get ();
2643 mono_class_init_internal (method->klass);
2645 code = mono_aot_get_method (domain, method, error);
2646 if (code) {
2647 MonoVTable *vtable;
2649 if (mono_gc_is_critical_method (method)) {
2651 * The suspend code needs to be able to lookup these methods by ip in async context,
2652 * so preload their jit info.
2654 MonoJitInfo *ji = mini_jit_info_table_find (domain, code, NULL);
2655 g_assert (ji);
2659 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2660 * This is not a problem, since it will be initialized when the method is first
2661 * called by init_method ().
2663 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2664 vtable = mono_class_vtable_checked (domain, method->klass, error);
2665 mono_error_assert_ok (error);
2666 if (!mono_runtime_class_init_full (vtable, error))
2667 return NULL;
2670 if (!is_ok (error))
2671 return NULL;
2673 #endif
2675 if (!code) {
2676 code = compile_special (method, target_domain, error);
2678 if (!is_ok (error))
2679 return NULL;
2682 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER) {
2683 if (mono_llvm_only) {
2684 /* Signal to the caller that AOTed code is not found */
2685 return NULL;
2687 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2689 if (!is_ok (error))
2690 return NULL;
2693 if (!code) {
2694 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2695 char *full_name = mono_type_get_full_name (method->klass);
2696 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2697 g_free (full_name);
2698 return NULL;
2701 if (mono_aot_only) {
2702 char *fullname = mono_method_get_full_name (method);
2703 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);
2704 g_free (fullname);
2706 return NULL;
2709 if (wait_or_register_method_to_compile (method, target_domain))
2710 goto lookup_start;
2711 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2712 unregister_method_for_compile (method, target_domain);
2714 if (!is_ok (error))
2715 return NULL;
2717 if (!code && mono_llvm_only) {
2718 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2719 g_assert_not_reached ();
2722 if (!code)
2723 return NULL;
2725 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2726 #ifndef HOST_WASM
2727 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2728 MonoDomain *d;
2731 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2733 MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2734 g_assert (ji);
2736 #endif
2738 p = mono_create_ftnptr (target_domain, code);
2740 if (callinfo) {
2741 // FIXME Locking here is somewhat historical due to mono_register_jit_icall_wrapper taking loader lock.
2742 // atomic_compare_exchange should suffice.
2743 mono_loader_lock ();
2744 mono_jit_lock ();
2745 if (!callinfo->wrapper) {
2746 callinfo->wrapper = p;
2748 mono_jit_unlock ();
2749 mono_loader_unlock ();
2752 // FIXME p or callinfo->wrapper or does not matter?
2753 return p;
2756 gpointer
2757 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2759 gpointer code;
2761 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2762 return code;
2766 * mono_jit_compile_method_jit_only:
2768 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2770 gpointer
2771 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2773 gpointer code;
2775 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2776 return code;
2779 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2780 static void
2781 invalidated_delegate_trampoline (char *desc)
2783 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2784 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2785 desc);
2787 #endif
2790 * mono_jit_free_method:
2792 * Free all memory allocated by the JIT for METHOD.
2794 static void
2795 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2797 MonoJitDynamicMethodInfo *ji;
2798 gboolean destroy = TRUE, removed;
2799 GHashTableIter iter;
2800 MonoJumpList *jlist;
2801 MonoJitDomainInfo *info = domain_jit_info (domain);
2803 g_assert (method->dynamic);
2805 if (mono_use_interpreter) {
2806 mini_get_interp_callbacks ()->free_method (domain, method);
2809 mono_domain_lock (domain);
2810 ji = mono_dynamic_code_hash_lookup (domain, method);
2811 mono_domain_unlock (domain);
2813 if (!ji)
2814 return;
2816 mono_debug_remove_method (method, domain);
2817 mono_lldb_remove_method (domain, method, ji);
2819 mono_domain_lock (domain);
2820 g_hash_table_remove (info->dynamic_code_hash, method);
2821 mono_domain_jit_code_hash_lock (domain);
2822 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2823 g_assert (removed);
2824 mono_domain_jit_code_hash_unlock (domain);
2825 g_hash_table_remove (info->jump_trampoline_hash, method);
2826 g_hash_table_remove (info->seq_points, method);
2828 ji->ji->seq_points = NULL;
2830 /* requires the domain lock - took above */
2831 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2833 /* Remove jump targets in this method */
2834 g_hash_table_iter_init (&iter, info->jump_target_hash);
2835 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2836 GSList *tmp, *remove;
2838 remove = NULL;
2839 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2840 guint8 *ip = (guint8 *)tmp->data;
2842 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2843 remove = g_slist_prepend (remove, tmp);
2845 for (tmp = remove; tmp; tmp = tmp->next) {
2846 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2848 g_slist_free (remove);
2850 mono_domain_unlock (domain);
2852 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2853 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2855 * Instead of freeing the code, change it to call an error routine
2856 * so people can fix their code.
2858 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2859 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2861 g_free (type);
2862 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2863 destroy = FALSE;
2865 #endif
2868 * This needs to be done before freeing code_mp, since the code address is the
2869 * key in the table, so if we free the code_mp first, another thread can grab the
2870 * same code address and replace our entry in the table.
2872 mono_jit_info_table_remove (domain, ji->ji);
2874 if (destroy)
2875 mono_code_manager_destroy (ji->code_mp);
2876 g_free (ji);
2879 gpointer
2880 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2882 gpointer code;
2883 MonoJitInfo *ji;
2885 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2886 if (!code) {
2887 ERROR_DECL (oerror);
2889 /* Might be AOTed code */
2890 mono_class_init_internal (method->klass);
2891 code = mono_aot_get_method (domain, method, oerror);
2892 if (code) {
2893 mono_error_assert_ok (oerror);
2894 ji = mono_jit_info_table_find (domain, code);
2895 } else {
2896 if (!is_ok (oerror))
2897 mono_error_cleanup (oerror);
2899 /* Might be interpreted */
2900 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2904 *out_ji = ji;
2906 return code;
2909 gpointer
2910 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2912 MonoDomain *target_domain;
2913 MonoJitInfo *info;
2915 if (default_opt & MONO_OPT_SHARED)
2916 target_domain = mono_get_root_domain ();
2917 else
2918 target_domain = domain;
2920 info = lookup_method (target_domain, method);
2921 if (info) {
2922 /* We can't use a domain specific method in another domain */
2923 if (! ((domain != target_domain) && !info->domain_neutral)) {
2924 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2925 if (ji)
2926 *ji = info;
2927 return MINI_ADDR_TO_FTNPTR (info->code_start);
2931 if (ji)
2932 *ji = NULL;
2933 return NULL;
2936 static guint32 bisect_opt = 0;
2937 static GHashTable *bisect_methods_hash = NULL;
2939 void
2940 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2942 FILE *file;
2943 char method_name [2048];
2945 bisect_opt = opt;
2946 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2947 g_assert (bisect_methods_hash);
2949 file = fopen (method_list_filename, "r");
2950 g_assert (file);
2952 while (fgets (method_name, sizeof (method_name), file)) {
2953 size_t len = strlen (method_name);
2954 g_assert (len > 0);
2955 g_assert (method_name [len - 1] == '\n');
2956 method_name [len - 1] = 0;
2957 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2959 g_assert (feof (file));
2962 gboolean mono_do_single_method_regression = FALSE;
2963 guint32 mono_single_method_regression_opt = 0;
2964 MonoMethod *mono_current_single_method;
2965 GSList *mono_single_method_list;
2966 GHashTable *mono_single_method_hash;
2968 guint32
2969 mono_get_optimizations_for_method (MonoMethod *method, guint32 opt)
2971 g_assert (method);
2973 if (bisect_methods_hash) {
2974 char *name = mono_method_full_name (method, TRUE);
2975 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2976 g_free (name);
2977 if (res)
2978 return opt | bisect_opt;
2980 if (!mono_do_single_method_regression)
2981 return opt;
2982 if (!mono_current_single_method) {
2983 if (!mono_single_method_hash)
2984 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2985 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2986 g_hash_table_insert (mono_single_method_hash, method, method);
2987 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2989 return opt;
2991 if (method == mono_current_single_method)
2992 return mono_single_method_regression_opt;
2993 return opt;
2996 gpointer
2997 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2999 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
3002 typedef struct {
3003 MonoMethod *method;
3004 gpointer compiled_method;
3005 gpointer runtime_invoke;
3006 MonoVTable *vtable;
3007 MonoDynCallInfo *dyn_call_info;
3008 MonoClass *ret_box_class;
3009 MonoMethodSignature *sig;
3010 gboolean gsharedvt_invoke;
3011 gboolean use_interp;
3012 gpointer *wrapper_arg;
3013 } RuntimeInvokeInfo;
3015 static RuntimeInvokeInfo*
3016 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
3018 MonoMethod *invoke;
3019 RuntimeInvokeInfo *info = NULL;
3020 RuntimeInvokeInfo *ret = NULL;
3022 info = g_new0 (RuntimeInvokeInfo, 1);
3023 info->compiled_method = compiled_method;
3024 info->use_interp = use_interp;
3025 if (mono_llvm_only && method->string_ctor)
3026 info->sig = mono_marshal_get_string_ctor_signature (method);
3027 else
3028 info->sig = mono_method_signature_internal (method);
3030 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
3031 (void)invoke;
3032 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
3033 if (!is_ok (error))
3034 goto exit;
3035 g_assert (info->vtable);
3037 MonoMethodSignature *sig;
3038 sig = info->sig;
3039 MonoType *ret_type;
3042 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
3043 * in full-aot mode, so we use a slower, but more generic wrapper if
3044 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
3046 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3047 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
3048 gboolean supported = TRUE;
3049 int i;
3051 if (method->string_ctor)
3052 sig = mono_marshal_get_string_ctor_signature (method);
3054 for (i = 0; i < sig->param_count; ++i) {
3055 MonoType *t = sig->params [i];
3057 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
3058 supported = FALSE;
3061 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
3062 supported = FALSE;
3064 if (supported) {
3065 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
3066 if (mini_debug_options.dyn_runtime_invoke)
3067 g_assert (info->dyn_call_info);
3070 #endif
3072 ret_type = sig->ret;
3073 switch (ret_type->type) {
3074 case MONO_TYPE_VOID:
3075 break;
3076 case MONO_TYPE_I1:
3077 case MONO_TYPE_U1:
3078 case MONO_TYPE_I2:
3079 case MONO_TYPE_U2:
3080 case MONO_TYPE_I4:
3081 case MONO_TYPE_U4:
3082 case MONO_TYPE_I:
3083 case MONO_TYPE_U:
3084 case MONO_TYPE_I8:
3085 case MONO_TYPE_U8:
3086 case MONO_TYPE_BOOLEAN:
3087 case MONO_TYPE_CHAR:
3088 case MONO_TYPE_R4:
3089 case MONO_TYPE_R8:
3090 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3091 break;
3092 case MONO_TYPE_PTR:
3093 info->ret_box_class = mono_defaults.int_class;
3094 break;
3095 case MONO_TYPE_STRING:
3096 case MONO_TYPE_CLASS:
3097 case MONO_TYPE_ARRAY:
3098 case MONO_TYPE_SZARRAY:
3099 case MONO_TYPE_OBJECT:
3100 break;
3101 case MONO_TYPE_GENERICINST:
3102 if (!MONO_TYPE_IS_REFERENCE (ret_type))
3103 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3104 break;
3105 case MONO_TYPE_VALUETYPE:
3106 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3107 break;
3108 default:
3109 g_assert_not_reached ();
3110 break;
3113 if (info->use_interp) {
3114 ret = info;
3115 info = NULL;
3116 goto exit;
3119 if (!info->dyn_call_info) {
3120 if (mono_llvm_only) {
3121 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
3122 g_assert_not_reached ();
3123 #endif
3124 info->gsharedvt_invoke = TRUE;
3125 if (!callee_gsharedvt) {
3126 /* Invoke a gsharedvt out wrapper instead */
3127 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
3128 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
3130 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
3131 info->wrapper_arg [0] = mini_llvmonly_add_method_wrappers (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
3133 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
3134 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
3135 g_free (wrapper_sig);
3137 info->compiled_method = mono_jit_compile_method (wrapper, error);
3138 if (!is_ok (error))
3139 goto exit;
3140 } else {
3141 /* Gsharedvt methods can be invoked the same way */
3142 /* The out wrapper has the same signature as the compiled gsharedvt method */
3143 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
3145 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
3147 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
3148 g_free (wrapper_sig);
3151 info->runtime_invoke = mono_jit_compile_method (invoke, error);
3152 if (!is_ok (error))
3153 goto exit;
3156 ret = info;
3157 info = NULL;
3158 exit:
3159 g_free (info);
3160 return ret;
3163 static MonoObject*
3164 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
3166 MonoMethodSignature *sig = info->sig;
3167 MonoDomain *domain = mono_domain_get ();
3168 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
3169 gpointer retval_ptr;
3170 guint8 retval [256];
3171 int i, pindex;
3173 error_init (error);
3175 g_assert (info->gsharedvt_invoke);
3178 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
3179 * The advantage of this is the gsharedvt out wrappers have a reduced set of
3180 * signatures, so we only have to generate runtime invoke wrappers for these
3181 * signatures.
3182 * This code also handles invocation of gsharedvt methods directly, no
3183 * out wrappers are used in that case.
3185 // allocate param_refs = param_count and args = param_count + hasthis + 2.
3186 int const param_count = sig->param_count;
3187 gpointer* const param_refs = g_newa (gpointer, param_count * 2 + sig->hasthis + 2);
3188 gpointer* const args = param_refs + param_count;
3189 pindex = 0;
3191 * The runtime invoke wrappers expects pointers to primitive types, so have to
3192 * use indirections.
3194 if (sig->hasthis)
3195 args [pindex ++] = &obj;
3196 if (sig->ret->type != MONO_TYPE_VOID) {
3197 retval_ptr = &retval;
3198 args [pindex ++] = &retval_ptr;
3200 for (i = 0; i < sig->param_count; ++i) {
3201 MonoType *t = sig->params [i];
3203 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
3204 MonoClass *klass = mono_class_from_mono_type_internal (t);
3205 guint8 *nullable_buf;
3206 int size;
3208 size = mono_class_value_size (klass, NULL);
3209 nullable_buf = g_alloca (size);
3210 g_assert (nullable_buf);
3212 /* The argument pointed to by params [i] is either a boxed vtype or null */
3213 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
3214 params [i] = nullable_buf;
3217 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
3218 param_refs [i] = params [i];
3219 params [i] = &(param_refs [i]);
3221 args [pindex ++] = &params [i];
3223 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
3224 args [pindex ++] = &info->wrapper_arg;
3226 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3228 runtime_invoke (NULL, args, exc, info->compiled_method);
3229 if (exc && *exc)
3230 return NULL;
3232 if (sig->ret->type != MONO_TYPE_VOID) {
3233 if (info->ret_box_class)
3234 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3235 else
3236 return *(MonoObject**)retval;
3237 } else {
3238 return NULL;
3243 * mono_jit_runtime_invoke:
3244 * \param method: the method to invoke
3245 * \param obj: this pointer
3246 * \param params: array of parameter values.
3247 * \param exc: Set to the exception raised in the managed method.
3248 * \param error: error or caught exception object
3249 * If \p exc is NULL, \p error is thrown instead.
3250 * If coop is enabled, \p exc argument is ignored -
3251 * all exceptions are caught and propagated through \p error
3253 static MonoObject*
3254 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
3256 MonoMethod *invoke, *callee;
3257 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
3258 MonoDomain *domain = mono_domain_get ();
3259 MonoJitDomainInfo *domain_info;
3260 RuntimeInvokeInfo *info, *info2;
3261 MonoJitInfo *ji = NULL;
3262 gboolean callee_gsharedvt = FALSE;
3264 if (mono_ee_features.force_use_interpreter)
3265 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3267 error_init (error);
3268 if (exc)
3269 *exc = NULL;
3271 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
3272 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3273 return NULL;
3276 domain_info = domain_jit_info (domain);
3278 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3280 if (!info) {
3281 if (mono_security_core_clr_enabled ()) {
3283 * This might be redundant since mono_class_vtable () already does this,
3284 * but keep it just in case for moonlight.
3286 mono_class_setup_vtable (method->klass);
3287 if (mono_class_has_failure (method->klass)) {
3288 mono_error_set_for_class_failure (error, method->klass);
3289 if (exc)
3290 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3291 return NULL;
3295 gpointer compiled_method;
3297 callee = method;
3298 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3299 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3301 * Array Get/Set/Address methods. The JIT implements them using inline code
3302 * inside the runtime invoke wrappers, so no need to compile them.
3304 if (mono_aot_only) {
3306 * Call a wrapper, since the runtime invoke wrapper was not generated.
3308 MonoMethod *wrapper;
3310 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3311 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3312 callee = wrapper;
3313 } else {
3314 callee = NULL;
3318 gboolean use_interp = FALSE;
3320 if (callee) {
3321 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3322 if (!compiled_method) {
3323 g_assert (!is_ok (error));
3325 if (mono_use_interpreter)
3326 use_interp = TRUE;
3327 else
3328 return NULL;
3329 } else {
3330 if (mono_llvm_only) {
3331 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3332 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3333 if (callee_gsharedvt)
3334 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3337 if (!callee_gsharedvt)
3338 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3340 } else {
3341 compiled_method = NULL;
3344 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3345 if (!is_ok (error))
3346 return NULL;
3348 mono_domain_lock (domain);
3349 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3350 mono_domain_unlock (domain);
3351 if (info2) {
3352 g_free (info);
3353 info = info2;
3358 * We need this here because mono_marshal_get_runtime_invoke can place
3359 * the helper method in System.Object and not the target class.
3361 if (!mono_runtime_class_init_full (info->vtable, error)) {
3362 if (exc)
3363 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3364 return NULL;
3367 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3368 we always catch the exception and propagate it through the MonoError */
3369 gboolean catchExcInMonoError =
3370 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3371 MonoObject *invoke_exc = NULL;
3372 if (catchExcInMonoError)
3373 exc = &invoke_exc;
3375 /* The wrappers expect this to be initialized to NULL */
3376 if (exc)
3377 *exc = NULL;
3379 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3380 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3381 if (info->dyn_call_info) {
3382 if (!dyn_runtime_invoke) {
3383 mono_domain_lock (domain);
3385 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3386 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3387 if (!dyn_runtime_invoke && mono_use_interpreter) {
3388 info->use_interp = TRUE;
3389 info->dyn_call_info = NULL;
3390 } else if (!is_ok (error)) {
3391 mono_domain_unlock (domain);
3392 return NULL;
3394 mono_domain_unlock (domain);
3397 if (info->dyn_call_info) {
3398 MonoMethodSignature *sig = mono_method_signature_internal (method);
3399 gpointer *args;
3400 int i, pindex, buf_size;
3401 guint8 *buf;
3402 guint8 retval [256];
3404 /* Convert the arguments to the format expected by start_dyn_call () */
3405 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3406 pindex = 0;
3407 if (sig->hasthis)
3408 args [pindex ++] = &obj;
3409 for (i = 0; i < sig->param_count; ++i) {
3410 MonoType *t = sig->params [i];
3412 if (t->byref) {
3413 args [pindex ++] = &params [i];
3414 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3415 args [pindex ++] = &params [i];
3416 } else {
3417 args [pindex ++] = params [i];
3421 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3423 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3424 buf = g_alloca (buf_size);
3425 memset (buf, 0, buf_size);
3426 g_assert (buf);
3428 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3430 dyn_runtime_invoke (buf, exc, info->compiled_method);
3431 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3433 if (catchExcInMonoError && *exc != NULL) {
3434 mono_error_set_exception_instance (error, (MonoException*) *exc);
3435 return NULL;
3438 if (info->ret_box_class)
3439 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3440 else
3441 return *(MonoObject**)retval;
3443 #endif
3445 MonoObject *result;
3447 if (info->use_interp) {
3448 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3449 return_val_if_nok (error, NULL);
3450 } else if (mono_llvm_only) {
3451 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3452 if (!is_ok (error))
3453 return NULL;
3454 } else {
3455 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3457 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3459 if (catchExcInMonoError && *exc != NULL) {
3460 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3461 mono_error_set_exception_instance (error, (MonoException*) *exc);
3463 return result;
3466 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3468 MonoException *exc = NULL;
3469 MonoJitInfo *ji;
3470 MonoContext mctx;
3471 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3472 MONO_SIG_HANDLER_GET_CONTEXT;
3474 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3476 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3478 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3479 if (mono_arch_is_int_overflow (ctx, info))
3481 * The spec says this throws ArithmeticException, but MS throws the derived
3482 * OverflowException.
3484 exc = mono_get_exception_overflow ();
3485 else
3486 exc = mono_get_exception_divide_by_zero ();
3487 #else
3488 exc = mono_get_exception_divide_by_zero ();
3489 #endif
3491 if (!ji) {
3492 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3493 goto exit;
3495 mono_sigctx_to_monoctx (ctx, &mctx);
3496 if (mono_dump_start ())
3497 mono_handle_native_crash (mono_get_signame (SIGFPE), &mctx, info);
3498 if (mono_do_crash_chaining) {
3499 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3500 goto exit;
3504 mono_arch_handle_exception (ctx, exc);
3506 exit:
3507 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3510 MONO_SIG_HANDLER_FUNC (, mono_crashing_signal_handler)
3512 MonoContext mctx;
3513 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3514 MONO_SIG_HANDLER_GET_CONTEXT;
3516 if (mono_runtime_get_no_exec ())
3517 exit (1);
3519 mono_sigctx_to_monoctx (ctx, &mctx);
3520 if (mono_dump_start ())
3521 #if defined(HAVE_SIG_INFO) && !defined(HOST_WIN32) // info is a siginfo_t
3522 mono_handle_native_crash (mono_get_signame (info->si_signo), &mctx, info);
3523 #else
3524 mono_handle_native_crash (mono_get_signame (SIGTERM), &mctx, info);
3525 #endif
3526 if (mono_do_crash_chaining) {
3527 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3528 return;
3532 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3534 #define HAVE_SIG_INFO
3535 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3537 #ifdef MONO_SIG_HANDLER_DEBUG
3538 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3539 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3540 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3541 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3542 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3543 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3544 #endif
3546 #endif
3548 gboolean
3549 mono_is_addr_implicit_null_check (void *addr)
3551 /* implicit null checks are only expected to work on the first page. larger
3552 * offsets are expected to have an explicit null check */
3553 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3556 // This function is separate from mono_sigsegv_signal_handler
3557 // so debug_fault_addr can be seen in debugger stacks.
3558 #ifdef MONO_SIG_HANDLER_DEBUG
3559 MONO_NEVER_INLINE
3560 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3561 #else
3562 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3563 #endif
3565 MonoJitInfo *ji = NULL;
3566 MonoDomain *domain = mono_domain_get ();
3567 gpointer fault_addr = NULL;
3568 MonoContext mctx;
3570 #if defined(HAVE_SIG_INFO) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3571 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3572 #endif
3573 #ifdef HAVE_SIG_INFO
3574 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3575 #else
3576 void *info = NULL;
3577 #endif
3578 MONO_SIG_HANDLER_GET_CONTEXT;
3580 mono_sigctx_to_monoctx (ctx, &mctx);
3582 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3583 if (mono_arch_is_single_step_event (info, ctx)) {
3584 mini_get_dbg_callbacks ()->single_step_event (ctx);
3585 return;
3586 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3587 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3588 return;
3590 #endif
3592 #if defined(HAVE_SIG_INFO)
3593 #if !defined(HOST_WIN32)
3594 fault_addr = info->si_addr;
3595 if (mono_aot_is_pagefault (info->si_addr)) {
3596 mono_aot_handle_pagefault (info->si_addr);
3597 return;
3599 int signo = info->si_signo;
3600 #else
3601 int signo = SIGSEGV;
3602 #endif
3604 /* The thread might no be registered with the runtime */
3605 if (!mono_domain_get () || !jit_tls) {
3606 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3607 return;
3608 if (mono_dump_start())
3609 mono_handle_native_crash (mono_get_signame (signo), &mctx, info);
3610 if (mono_do_crash_chaining) {
3611 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3612 return;
3614 /* thread not registered with the runtime, make sure we return now. */
3615 return;
3617 #endif
3619 if (domain) {
3620 gpointer ip = MINI_FTNPTR_TO_ADDR (mono_arch_ip_from_context (ctx));
3621 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
3624 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3625 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3626 return;
3628 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3629 fault_addr = info->si_addr;
3630 if (fault_addr == NULL) {
3631 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3634 if (jit_tls && jit_tls->stack_size &&
3635 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3637 * The hard-guard page has been hit: there is not much we can do anymore
3638 * Print a hopefully clear message and abort.
3640 mono_handle_hard_stack_ovf (jit_tls, ji, &mctx, (guint8*)info->si_addr);
3641 g_assert_not_reached ();
3642 } else {
3643 /* The original handler might not like that it is executed on an altstack... */
3644 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3645 return;
3647 #ifdef TARGET_AMD64
3648 /* exceptions-amd64.c handles the check itself */
3649 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3650 #else
3651 if (mono_is_addr_implicit_null_check (info->si_addr)) {
3652 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3653 } else {
3654 // FIXME: This shouldn't run on the altstack
3655 if (mono_dump_start ())
3656 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, info);
3658 #endif
3660 #else
3662 if (!ji) {
3663 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3664 return;
3666 if (mono_dump_start ())
3667 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3669 if (mono_do_crash_chaining) {
3670 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3671 return;
3675 if (mono_is_addr_implicit_null_check (fault_addr)) {
3676 mono_arch_handle_exception (ctx, NULL);
3677 } else {
3678 if (mono_dump_start ())
3679 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3680 if (mono_do_crash_chaining) {
3681 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3682 return;
3685 #endif
3688 #ifdef MONO_SIG_HANDLER_DEBUG
3690 // This function is separate from mono_sigsegv_signal_handler_debug
3691 // so debug_fault_addr can be seen in debugger stacks.
3692 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3694 #ifdef HOST_WIN32
3695 gpointer const debug_fault_addr = (gpointer)MONO_SIG_HANDLER_GET_INFO () ->ep->ExceptionRecord->ExceptionInformation [1];
3696 #elif defined (HAVE_SIG_INFO)
3697 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3698 #else
3699 #error No extra parameter is passed, not even 0, to avoid any confusion.
3700 #endif
3701 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3704 #endif // MONO_SIG_HANDLER_DEBUG
3706 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3708 MonoException *exc;
3709 MONO_SIG_HANDLER_GET_CONTEXT;
3711 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3713 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3715 mono_arch_handle_exception (ctx, exc);
3717 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3720 #ifndef DISABLE_REMOTING
3721 /* mono_jit_create_remoting_trampoline:
3722 * @method: pointer to the method info
3724 * Creates a trampoline which calls the remoting functions. This
3725 * is used in the vtable of transparent proxies.
3727 * Returns: a pointer to the newly created code
3729 static gpointer
3730 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3732 MonoMethod *nm;
3733 guint8 *addr = NULL;
3735 error_init (error);
3737 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3738 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3739 domain, NULL);
3742 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3743 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3744 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3745 else
3746 nm = method;
3747 return_val_if_nok (error, NULL);
3748 addr = (guint8 *)mono_compile_method_checked (nm, error);
3749 return_val_if_nok (error, NULL);
3750 return mono_get_addr_from_ftnptr (addr);
3752 #endif
3754 static G_GNUC_UNUSED void
3755 no_imt_trampoline (void)
3757 g_assert_not_reached ();
3760 static G_GNUC_UNUSED void
3761 no_vcall_trampoline (void)
3763 g_assert_not_reached ();
3766 static gpointer *vtable_trampolines;
3767 static int vtable_trampolines_size;
3769 gpointer
3770 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3772 int index = slot_index + MONO_IMT_SIZE;
3774 if (mono_llvm_only)
3775 return mini_llvmonly_get_vtable_trampoline (vt, slot_index, index);
3777 g_assert (slot_index >= - MONO_IMT_SIZE);
3778 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3779 mono_jit_lock ();
3780 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3781 int new_size;
3782 gpointer new_table;
3784 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3785 while (new_size <= index)
3786 new_size *= 2;
3787 new_table = g_new0 (gpointer, new_size);
3789 if (vtable_trampolines)
3790 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3791 g_free (vtable_trampolines);
3792 mono_memory_barrier ();
3793 vtable_trampolines = (void **)new_table;
3794 vtable_trampolines_size = new_size;
3796 mono_jit_unlock ();
3799 if (!vtable_trampolines [index])
3800 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3801 return vtable_trampolines [index];
3804 static gpointer
3805 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3807 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3810 static gboolean
3811 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3813 if (mono_llvm_only)
3814 return FALSE;
3816 gpointer *imt = (gpointer*)vt;
3817 imt -= MONO_IMT_SIZE;
3819 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3822 static gpointer
3823 create_delegate_method_ptr (MonoMethod *method, MonoError *error)
3825 gpointer func;
3827 if (method_is_dynamic (method)) {
3828 /* Creating a trampoline would leak memory */
3829 func = mono_compile_method_checked (method, error);
3830 return_val_if_nok (error, NULL);
3831 } else {
3832 gpointer trampoline = mono_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
3833 return_val_if_nok (error, NULL);
3834 func = mono_create_ftnptr (mono_domain_get (), trampoline);
3836 return func;
3839 static void
3840 mini_init_delegate (MonoDelegateHandle delegate, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
3842 MonoDelegate *del = MONO_HANDLE_RAW (delegate);
3843 MonoDomain *domain = MONO_HANDLE_DOMAIN (delegate);
3845 if (!method) {
3846 MonoJitInfo *ji;
3847 gpointer lookup_addr = MINI_FTNPTR_TO_ADDR (addr);
3849 g_assert (addr);
3850 ji = mono_jit_info_table_find_internal (domain, mono_get_addr_from_ftnptr (lookup_addr), TRUE, TRUE);
3851 /* Shared code */
3852 if (!ji && domain != mono_get_root_domain ())
3853 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), mono_get_addr_from_ftnptr (lookup_addr), TRUE, TRUE);
3854 if (ji) {
3855 if (ji->is_trampoline) {
3856 /* Could be an unbox trampoline etc. */
3857 method = ji->d.tramp_info->method;
3858 } else {
3859 method = mono_jit_info_get_method (ji);
3860 g_assert (!mono_class_is_gtd (method->klass));
3865 if (method)
3866 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
3868 if (addr)
3869 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
3871 #ifndef DISABLE_REMOTING
3872 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
3873 if (mono_use_interpreter) {
3874 MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, mini_get_interp_callbacks ()->get_remoting_invoke (method, addr, error));
3875 } else {
3876 g_assert (method);
3877 method = mono_marshal_get_remoting_invoke (method, error);
3878 return_if_nok (error);
3879 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
3881 return_if_nok (error);
3883 #endif
3885 MONO_HANDLE_SET (delegate, target, target);
3886 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, mono_create_delegate_trampoline (domain, mono_handle_class (delegate)));
3888 if (mono_use_interpreter) {
3889 mini_get_interp_callbacks ()->init_delegate (del, error);
3890 return_if_nok (error);
3893 if (mono_llvm_only) {
3894 g_assert (del->method);
3895 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3896 del->method_ptr = mini_llvmonly_load_method_delegate (del->method, FALSE, FALSE, &del->extra_arg, error);
3897 } else if (!del->method_ptr) {
3898 del->method_ptr = create_delegate_method_ptr (del->method, error);
3899 return_if_nok (error);
3903 char*
3904 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3906 int abs_offset;
3908 abs_offset = offset;
3909 if (abs_offset < 0)
3910 abs_offset = - abs_offset;
3911 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3914 gpointer
3915 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3917 gboolean is_virtual_generic, is_interface, load_imt_reg;
3918 int offset, idx;
3920 static guint8 **cache = NULL;
3921 static int cache_size = 0;
3923 if (!method)
3924 return NULL;
3926 if (MONO_TYPE_ISSTRUCT (sig->ret))
3927 return NULL;
3929 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3930 is_interface = mono_class_is_interface (method->klass);
3931 load_imt_reg = is_virtual_generic || is_interface;
3933 if (is_interface)
3934 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3935 else
3936 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3938 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3939 g_assert (idx >= 0);
3941 /* Resize the cache to idx + 1 */
3942 if (cache_size < idx + 1) {
3943 mono_jit_lock ();
3944 if (cache_size < idx + 1) {
3945 guint8 **new_cache;
3946 int new_cache_size = idx + 1;
3948 new_cache = g_new0 (guint8*, new_cache_size);
3949 if (cache)
3950 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3951 g_free (cache);
3953 mono_memory_barrier ();
3954 cache = new_cache;
3955 cache_size = new_cache_size;
3957 mono_jit_unlock ();
3960 if (cache [idx])
3961 return cache [idx];
3963 /* FIXME Support more cases */
3964 if (mono_ee_features.use_aot_trampolines) {
3965 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3966 g_assert (cache [idx]);
3967 } else {
3968 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3970 return cache [idx];
3974 * mini_parse_debug_option:
3975 * @option: The option to parse.
3977 * Parses debug options for the mono runtime. The options are the same as for
3978 * the MONO_DEBUG environment variable.
3981 gboolean
3982 mini_parse_debug_option (const char *option)
3984 // Empty string is ok as consequence of appending ",foo"
3985 // without first checking for empty.
3986 if (*option == 0)
3987 return TRUE;
3989 if (!strcmp (option, "handle-sigint"))
3990 mini_debug_options.handle_sigint = TRUE;
3991 else if (!strcmp (option, "keep-delegates"))
3992 mini_debug_options.keep_delegates = TRUE;
3993 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3994 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3995 else if (!strcmp (option, "collect-pagefault-stats"))
3996 mini_debug_options.collect_pagefault_stats = TRUE;
3997 else if (!strcmp (option, "break-on-unverified"))
3998 mini_debug_options.break_on_unverified = TRUE;
3999 else if (!strcmp (option, "no-gdb-backtrace"))
4000 mini_debug_options.no_gdb_backtrace = TRUE;
4001 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
4002 mini_debug_options.suspend_on_native_crash = TRUE;
4003 else if (!strcmp (option, "suspend-on-exception"))
4004 mini_debug_options.suspend_on_exception = TRUE;
4005 else if (!strcmp (option, "suspend-on-unhandled"))
4006 mini_debug_options.suspend_on_unhandled = TRUE;
4007 else if (!strcmp (option, "dont-free-domains"))
4008 mono_dont_free_domains = TRUE;
4009 else if (!strcmp (option, "dyn-runtime-invoke"))
4010 mini_debug_options.dyn_runtime_invoke = TRUE;
4011 else if (!strcmp (option, "gdb"))
4012 mini_debug_options.gdb = TRUE;
4013 else if (!strcmp (option, "lldb"))
4014 mini_debug_options.lldb = TRUE;
4015 else if (!strcmp (option, "llvm-disable-inlining"))
4016 mini_debug_options.llvm_disable_inlining = TRUE;
4017 else if (!strcmp (option, "llvm-disable-implicit-null-checks"))
4018 mini_debug_options.llvm_disable_implicit_null_checks = TRUE;
4019 else if (!strcmp (option, "explicit-null-checks"))
4020 mini_debug_options.explicit_null_checks = TRUE;
4021 else if (!strcmp (option, "gen-seq-points"))
4022 mini_debug_options.gen_sdb_seq_points = TRUE;
4023 else if (!strcmp (option, "gen-compact-seq-points"))
4024 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
4025 else if (!strcmp (option, "no-compact-seq-points"))
4026 mini_debug_options.no_seq_points_compact_data = TRUE;
4027 else if (!strcmp (option, "single-imm-size"))
4028 mini_debug_options.single_imm_size = TRUE;
4029 else if (!strcmp (option, "init-stacks"))
4030 mini_debug_options.init_stacks = TRUE;
4031 else if (!strcmp (option, "casts"))
4032 mini_debug_options.better_cast_details = TRUE;
4033 else if (!strcmp (option, "soft-breakpoints"))
4034 mini_debug_options.soft_breakpoints = TRUE;
4035 else if (!strcmp (option, "check-pinvoke-callconv"))
4036 mini_debug_options.check_pinvoke_callconv = TRUE;
4037 else if (!strcmp (option, "use-fallback-tls"))
4038 mini_debug_options.use_fallback_tls = TRUE;
4039 else if (!strcmp (option, "debug-domain-unload"))
4040 mono_enable_debug_domain_unload (TRUE);
4041 else if (!strcmp (option, "partial-sharing"))
4042 mono_set_partial_sharing_supported (TRUE);
4043 else if (!strcmp (option, "align-small-structs"))
4044 mono_align_small_structs = TRUE;
4045 else if (!strcmp (option, "native-debugger-break"))
4046 mini_debug_options.native_debugger_break = TRUE;
4047 else if (!strcmp (option, "disable_omit_fp"))
4048 mini_debug_options.disable_omit_fp = TRUE;
4049 // This is an internal testing feature.
4050 // Every tail. encountered is required to be optimized.
4051 // It is asserted.
4052 else if (!strcmp (option, "test-tailcall-require"))
4053 mini_debug_options.test_tailcall_require = TRUE;
4054 else if (!strcmp (option, "verbose-gdb"))
4055 mini_debug_options.verbose_gdb = TRUE;
4056 else if (!strcmp (option, "clr-memory-model"))
4057 // FIXME Kill this debug flag
4058 mini_debug_options.weak_memory_model = FALSE;
4059 else if (!strcmp (option, "weak-memory-model"))
4060 mini_debug_options.weak_memory_model = TRUE;
4061 else if (!strcmp (option, "top-runtime-invoke-unhandled"))
4062 mini_debug_options.top_runtime_invoke_unhandled = TRUE;
4063 else if (!strncmp (option, "thread-dump-dir=", 16))
4064 mono_set_thread_dump_dir(g_strdup(option + 16));
4065 else if (!strncmp (option, "aot-skip=", 9)) {
4066 mini_debug_options.aot_skip_set = TRUE;
4067 mini_debug_options.aot_skip = atoi (option + 9);
4068 } else
4069 return FALSE;
4071 return TRUE;
4074 static void
4075 mini_parse_debug_options (void)
4077 char *options = g_getenv ("MONO_DEBUG");
4078 gchar **args, **ptr;
4080 if (!options)
4081 return;
4083 args = g_strsplit (options, ",", -1);
4084 g_free (options);
4086 for (ptr = args; ptr && *ptr; ptr++) {
4087 const char *arg = *ptr;
4089 if (!mini_parse_debug_option (arg)) {
4090 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
4091 // test-tailcall-require is also accepted but not documented.
4092 // empty string is also accepted and ignored as a consequence
4093 // of appending ",foo" without checking for empty.
4094 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");
4095 exit (1);
4099 g_strfreev (args);
4102 MonoDebugOptions *
4103 mini_get_debug_options (void)
4105 return &mini_debug_options;
4108 static gpointer
4109 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
4111 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4112 gpointer* desc = NULL;
4114 if ((desc = (gpointer*)g_hash_table_lookup (domain->ftnptrs_hash, addr)))
4115 return desc;
4116 #if defined(__mono_ppc64__)
4117 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
4119 desc [0] = addr;
4120 desc [1] = NULL;
4121 desc [2] = NULL;
4122 # endif
4123 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
4124 return desc;
4125 #else
4126 return addr;
4127 #endif
4130 static gpointer
4131 mini_get_addr_from_ftnptr (gpointer descr)
4133 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4134 return *(gpointer*)descr;
4135 #else
4136 return descr;
4137 #endif
4140 static void
4141 register_counters (void)
4143 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
4144 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
4145 mono_counters_register ("Methods from AOT+LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot_llvm);
4146 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
4147 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
4148 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
4151 static void runtime_invoke_info_free (gpointer value);
4153 static gint
4154 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
4156 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
4157 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
4159 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
4162 static guint
4163 class_method_pair_hash (gconstpointer data)
4165 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
4167 return (gsize)pair->klass ^ (gsize)pair->method;
4170 static void
4171 mini_create_jit_domain_info (MonoDomain *domain)
4173 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
4175 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4176 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4177 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
4178 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4179 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
4180 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
4181 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
4182 info->jump_target_hash = g_hash_table_new (NULL, NULL);
4183 mono_jit_code_hash_init (&info->interp_code_hash);
4185 domain->runtime_info = info;
4188 static void
4189 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
4191 MonoJumpList *jlist = (MonoJumpList *)value;
4192 g_slist_free ((GSList*)jlist->list);
4195 static void
4196 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
4198 GSList *list = (GSList *)value;
4199 g_slist_free (list);
4202 static void
4203 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
4205 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
4206 mono_code_manager_destroy (di->code_mp);
4207 g_free (di);
4210 static void
4211 runtime_invoke_info_free (gpointer value)
4213 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
4215 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4216 if (info->dyn_call_info)
4217 mono_arch_dyn_call_free (info->dyn_call_info);
4218 #endif
4219 g_free (info);
4222 static void
4223 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
4225 g_slist_free ((GSList*)value);
4228 static void
4229 mini_free_jit_domain_info (MonoDomain *domain)
4231 MonoJitDomainInfo *info = domain_jit_info (domain);
4233 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
4234 g_hash_table_destroy (info->jump_target_hash);
4235 if (info->jump_target_got_slot_hash) {
4236 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
4237 g_hash_table_destroy (info->jump_target_got_slot_hash);
4239 if (info->dynamic_code_hash) {
4240 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
4241 g_hash_table_destroy (info->dynamic_code_hash);
4243 g_hash_table_destroy (info->method_code_hash);
4244 g_hash_table_destroy (info->jump_trampoline_hash);
4245 g_hash_table_destroy (info->jit_trampoline_hash);
4246 g_hash_table_destroy (info->delegate_trampoline_hash);
4247 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
4248 g_hash_table_destroy (info->mrgctx_hash);
4249 g_hash_table_destroy (info->method_rgctx_hash);
4250 g_hash_table_destroy (info->interp_method_pointer_hash);
4251 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
4252 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
4253 g_hash_table_destroy (info->seq_points);
4254 g_hash_table_destroy (info->arch_seq_points);
4255 if (info->agent_info)
4256 mini_get_dbg_callbacks ()->free_domain_info (domain);
4257 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
4258 if (info->llvm_jit_callees) {
4259 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
4260 g_hash_table_destroy (info->llvm_jit_callees);
4262 mono_internal_hash_table_destroy (&info->interp_code_hash);
4263 #ifdef ENABLE_LLVM
4264 mono_llvm_free_domain_info (domain);
4265 #endif
4267 g_free (domain->runtime_info);
4268 domain->runtime_info = NULL;
4271 #ifdef ENABLE_LLVM
4272 static gboolean
4273 llvm_init_inner (void)
4275 mono_llvm_init (!mono_compile_aot);
4276 return TRUE;
4278 #endif
4281 * mini_llvm_init:
4283 * Load and initialize LLVM support.
4284 * Return TRUE on success.
4286 gboolean
4287 mini_llvm_init (void)
4289 #ifdef ENABLE_LLVM
4290 static gboolean llvm_inited;
4291 static gboolean init_result;
4293 mono_loader_lock_if_inited ();
4294 if (!llvm_inited) {
4295 init_result = llvm_init_inner ();
4296 llvm_inited = TRUE;
4298 mono_loader_unlock_if_inited ();
4299 return init_result;
4300 #else
4301 return FALSE;
4302 #endif
4305 void
4306 mini_add_profiler_argument (const char *desc)
4308 if (!profile_options)
4309 profile_options = g_ptr_array_new ();
4311 g_ptr_array_add (profile_options, (gpointer) g_strdup (desc));
4315 const MonoEECallbacks *mono_interp_callbacks_pointer;
4317 void
4318 mini_install_interp_callbacks (const MonoEECallbacks *cbs)
4320 mono_interp_callbacks_pointer = cbs;
4323 static MonoDebuggerCallbacks dbg_cbs;
4325 void
4326 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4328 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4329 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4332 MonoDebuggerCallbacks*
4333 mini_get_dbg_callbacks (void)
4335 return &dbg_cbs;
4339 mono_ee_api_version (void)
4341 return MONO_EE_API_VERSION;
4344 void
4345 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4347 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4350 void
4351 mono_interp_to_native_trampoline (gpointer addr, gpointer ccontext)
4353 mini_get_interp_callbacks ()->to_native_trampoline (addr, ccontext);
4356 static gboolean
4357 mini_is_interpreter_enabled (void)
4359 return mono_use_interpreter;
4362 static const char*
4363 mono_get_runtime_build_version (void);
4365 MonoDomain *
4366 mini_init (const char *filename, const char *runtime_version)
4368 ERROR_DECL (error);
4369 MonoDomain *domain;
4371 MonoRuntimeCallbacks callbacks;
4373 static const MonoThreadInfoRuntimeCallbacks ticallbacks = {
4374 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK, mono)
4377 MONO_VES_INIT_BEGIN ();
4379 CHECKED_MONO_INIT ();
4381 #if defined(__linux__)
4382 if (access ("/proc/self/maps", F_OK) != 0) {
4383 g_print ("Mono requires /proc to be mounted.\n");
4384 exit (1);
4386 #endif
4388 mono_debugger_agent_stub_init ();
4389 #ifndef DISABLE_SDB
4390 mono_debugger_agent_init ();
4391 #endif
4393 if (sdb_options)
4394 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4396 mono_interp_stub_init ();
4397 #ifndef DISABLE_INTERPRETER
4398 if (mono_use_interpreter)
4399 mono_ee_interp_init (mono_interp_opts_string);
4400 #endif
4402 mono_os_mutex_init_recursive (&jit_mutex);
4404 mono_cross_helpers_run ();
4406 mono_counters_init ();
4408 mini_jit_init ();
4410 mini_jit_init_job_control ();
4412 /* Happens when using the embedding interface */
4413 if (!default_opt_set)
4414 default_opt = mono_parse_default_optimizations (NULL);
4416 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4417 if (mono_aot_only)
4418 mono_set_generic_sharing_vt_supported (TRUE);
4419 #else
4420 if (mono_llvm_only)
4421 mono_set_generic_sharing_vt_supported (TRUE);
4422 #endif
4424 mono_tls_init_runtime_keys ();
4426 if (!global_codeman)
4427 global_codeman = mono_code_manager_new ();
4429 memset (&callbacks, 0, sizeof (callbacks));
4430 callbacks.create_ftnptr = mini_create_ftnptr;
4431 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4432 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4433 callbacks.get_runtime_build_version = mono_get_runtime_build_version;
4434 callbacks.set_cast_details = mono_set_cast_details;
4435 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4436 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4437 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4438 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4439 callbacks.imt_entry_inited = mini_imt_entry_inited;
4440 callbacks.init_delegate = mini_init_delegate;
4441 #define JIT_INVOKE_WORKS
4442 #ifdef JIT_INVOKE_WORKS
4443 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4444 #endif
4445 #define JIT_TRAMPOLINES_WORK
4446 #ifdef JIT_TRAMPOLINES_WORK
4447 callbacks.compile_method = mono_jit_compile_method;
4448 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4449 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4450 callbacks.free_method = mono_jit_free_method;
4451 #ifndef DISABLE_REMOTING
4452 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4453 #endif
4454 #endif
4455 #ifndef DISABLE_REMOTING
4456 if (mono_use_interpreter)
4457 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4458 #endif
4459 callbacks.is_interpreter_enabled = mini_is_interpreter_enabled;
4460 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4462 #ifndef DISABLE_CRASH_REPORTING
4463 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4464 #endif
4465 #ifdef ENABLE_METADATA_UPDATE
4466 callbacks.metadata_update_init = mini_metadata_update_init;
4467 callbacks.metadata_update_published = mini_invalidate_transformed_interp_methods;
4468 #endif
4470 mono_install_callbacks (&callbacks);
4472 #ifndef HOST_WIN32
4473 mono_w32handle_init ();
4474 #endif
4476 mono_thread_info_runtime_init (&ticallbacks);
4478 if (g_hasenv ("MONO_DEBUG")) {
4479 mini_parse_debug_options ();
4482 mono_code_manager_init ();
4484 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4486 static const MonoCodeManagerCallbacks code_manager_callbacks = {
4488 #undef MONO_CODE_MANAGER_CALLBACK
4489 #define MONO_CODE_MANAGER_CALLBACK(ret, name, sig) mono_arch_code_ ## name,
4490 MONO_CODE_MANAGER_CALLBACKS
4494 mono_code_manager_install_callbacks (&code_manager_callbacks);
4495 #endif
4497 mono_hwcap_init ();
4499 mono_arch_cpu_init ();
4501 mono_arch_init ();
4503 mono_unwind_init ();
4505 if (mini_debug_options.lldb || g_hasenv ("MONO_LLDB")) {
4506 mono_lldb_init ("");
4507 mono_dont_free_domains = TRUE;
4510 #ifdef XDEBUG_ENABLED
4511 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4512 if (mono_xdebug) {
4513 mono_xdebug_init (mono_xdebug);
4514 g_free (mono_xdebug);
4515 /* So methods for multiple domains don't have the same address */
4516 mono_dont_free_domains = TRUE;
4517 mono_using_xdebug = TRUE;
4518 } else if (mini_debug_options.gdb) {
4519 mono_xdebug_init ((char*)"gdb");
4520 mono_dont_free_domains = TRUE;
4521 mono_using_xdebug = TRUE;
4523 #endif
4525 #ifdef ENABLE_LLVM
4526 if (mono_use_llvm)
4527 mono_llvm_init (!mono_compile_aot);
4528 #endif
4530 mono_trampolines_init ();
4532 if (default_opt & MONO_OPT_AOT)
4533 mono_aot_init ();
4535 mini_get_dbg_callbacks ()->init ();
4537 #ifdef TARGET_WASM
4538 mono_wasm_debugger_init ();
4539 #endif
4541 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4542 mono_set_generic_sharing_supported (TRUE);
4543 #endif
4545 mono_thread_info_signals_init ();
4547 mono_init_native_crash_info ();
4549 #ifndef MONO_CROSS_COMPILE
4550 mono_runtime_install_handlers ();
4551 #endif
4552 mono_threads_install_cleanup (mini_thread_cleanup);
4554 #ifdef JIT_TRAMPOLINES_WORK
4555 mono_install_create_domain_hook (mini_create_jit_domain_info);
4556 mono_install_free_domain_hook (mini_free_jit_domain_info);
4557 #endif
4558 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4559 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4560 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4562 mono_profiler_state.context_enable = mini_profiler_context_enable;
4563 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4564 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4565 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4566 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4567 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4569 if (g_hasenv ("MONO_PROFILE")) {
4570 gchar *profile_env = g_getenv ("MONO_PROFILE");
4571 mini_add_profiler_argument (profile_env);
4572 g_free (profile_env);
4575 if (profile_options)
4576 for (guint i = 0; i < profile_options->len; i++)
4577 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4579 mono_profiler_started ();
4581 if (mini_debug_options.collect_pagefault_stats)
4582 mono_aot_set_make_unreadable (TRUE);
4584 if (runtime_version)
4585 domain = mono_init_version (filename, runtime_version);
4586 else
4587 domain = mono_init_from_assembly (filename, filename);
4589 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
4590 if (mono_compile_aot)
4591 ds_server_disable ();
4593 ep_init ();
4594 #endif
4596 if (mono_aot_only) {
4597 /* This helps catch code allocation requests */
4598 mono_code_manager_set_read_only (mono_domain_ambient_memory_manager (domain)->code_mp);
4599 mono_marshal_use_aot_wrappers (TRUE);
4602 if (mono_llvm_only) {
4603 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline);
4604 mono_set_always_build_imt_trampolines (TRUE);
4605 } else if (mono_aot_only) {
4606 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4607 } else {
4608 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4611 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4612 mono_arch_finish_init ();
4614 /* This must come after mono_init () in the aot-only case */
4615 mono_exceptions_init ();
4617 /* This should come after mono_init () too */
4618 mini_gc_init ();
4620 mono_create_icall_signatures ();
4622 register_counters ();
4624 #define JIT_CALLS_WORK
4625 #ifdef JIT_CALLS_WORK
4626 /* Needs to be called here since register_jit_icall depends on it */
4627 mono_marshal_init ();
4629 mono_arch_register_lowlevel_calls ();
4631 register_icalls ();
4633 mono_generic_sharing_init ();
4634 #endif
4636 #ifdef MONO_ARCH_SIMD_INTRINSICS
4637 mono_simd_intrinsics_init ();
4638 #endif
4640 mono_tasklets_init ();
4642 register_trampolines (domain);
4644 if (mono_compile_aot)
4646 * Avoid running managed code when AOT compiling, since the platform
4647 * might only support aot-only execution.
4649 mono_runtime_set_no_exec (TRUE);
4651 mono_mem_account_register_counters ();
4653 #define JIT_RUNTIME_WORKS
4654 #ifdef JIT_RUNTIME_WORKS
4655 mono_install_runtime_cleanup (runtime_cleanup);
4656 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4657 mono_error_assert_ok (error);
4658 mono_thread_internal_attach (domain);
4659 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4660 #endif
4661 mono_threads_set_runtime_startup_finished ();
4663 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
4664 ep_finish_init ();
4665 #endif
4667 #ifdef ENABLE_EXPERIMENT_TIERED
4668 if (!mono_compile_aot) {
4669 /* create compilation thread in background */
4670 mini_tiered_init ();
4672 #endif
4674 if (mono_profiler_sampling_enabled ())
4675 mono_runtime_setup_stat_profiler ();
4677 MONO_PROFILER_RAISE (runtime_initialized, ());
4679 MONO_VES_INIT_END ();
4681 return domain;
4684 static void
4685 register_icalls (void)
4687 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4688 ves_icall_get_frame_info);
4689 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4690 ves_icall_get_trace);
4691 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4692 mono_runtime_install_handlers);
4693 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4694 mono_runtime_cleanup_handlers);
4696 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4697 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4698 mini_get_dbg_callbacks ()->unhandled_exception);
4699 #endif
4702 * It's important that we pass `TRUE` as the last argument here, as
4703 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4704 * *did* emit a wrapper, we'd be looking at infinite recursion since
4705 * the wrapper would call the icall which would call the wrapper and
4706 * so on.
4708 register_icall (mono_profiler_raise_method_enter, mono_icall_sig_void_ptr_ptr, TRUE);
4709 register_icall (mono_profiler_raise_method_leave, mono_icall_sig_void_ptr_ptr, TRUE);
4710 register_icall (mono_profiler_raise_method_tail_call, mono_icall_sig_void_ptr_ptr, TRUE);
4711 register_icall (mono_profiler_raise_exception_clause, mono_icall_sig_void_ptr_int_int_object, TRUE);
4713 register_icall (mono_trace_enter_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4714 register_icall (mono_trace_leave_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4715 register_icall (mono_trace_tail_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4716 g_assert (mono_get_lmf_addr == mono_tls_get_lmf_addr);
4717 register_icall (mono_jit_set_domain, mono_icall_sig_void_ptr, TRUE);
4718 register_icall (mono_domain_get, mono_icall_sig_ptr, TRUE);
4720 register_icall (mono_llvm_throw_exception, mono_icall_sig_void_object, TRUE);
4721 register_icall (mono_llvm_rethrow_exception, mono_icall_sig_void_object, TRUE);
4722 register_icall (mono_llvm_resume_exception, mono_icall_sig_void, TRUE);
4723 register_icall (mono_llvm_match_exception, mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
4724 register_icall (mono_llvm_clear_exception, NULL, TRUE);
4725 register_icall (mono_llvm_load_exception, mono_icall_sig_object, TRUE);
4726 register_icall (mono_llvm_throw_corlib_exception, mono_icall_sig_void_int, TRUE);
4727 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4728 register_icall (mono_llvm_set_unhandled_exception_handler, NULL, TRUE);
4730 // FIXME: This is broken
4731 #ifndef TARGET_WASM
4732 register_icall (mono_debug_personality, mono_icall_sig_int_int_int_ptr_ptr_ptr, TRUE);
4733 #endif
4734 #endif
4736 if (!mono_llvm_only) {
4737 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception, mono_icall_sig_void_object, TRUE);
4738 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception, mono_icall_sig_void_object, TRUE);
4739 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception, mono_icall_sig_void_ptr, TRUE);
4741 register_icall (mono_thread_get_undeniable_exception, mono_icall_sig_object, FALSE);
4742 register_icall (ves_icall_thread_finish_async_abort, mono_icall_sig_void, FALSE);
4743 register_icall (mono_thread_interruption_checkpoint, mono_icall_sig_object, FALSE);
4744 register_icall (mono_thread_force_interruption_checkpoint_noraise, mono_icall_sig_object, FALSE);
4746 register_icall (mono_threads_state_poll, mono_icall_sig_void, FALSE);
4748 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4749 register_opcode_emulation (OP_LMUL, __emul_lmul, mono_icall_sig_long_long_long, mono_llmult, FALSE);
4750 register_opcode_emulation (OP_LDIV, __emul_ldiv, mono_icall_sig_long_long_long, mono_lldiv, FALSE);
4751 register_opcode_emulation (OP_LDIV_UN, __emul_ldiv_un, mono_icall_sig_long_long_long, mono_lldiv_un, FALSE);
4752 register_opcode_emulation (OP_LREM, __emul_lrem, mono_icall_sig_long_long_long, mono_llrem, FALSE);
4753 register_opcode_emulation (OP_LREM_UN, __emul_lrem_un, mono_icall_sig_long_long_long, mono_llrem_un, FALSE);
4754 #endif
4755 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4756 register_opcode_emulation (OP_LMUL_OVF_UN, __emul_lmul_ovf_un, mono_icall_sig_long_long_long, mono_llmult_ovf_un, FALSE);
4757 register_opcode_emulation (OP_LMUL_OVF, __emul_lmul_ovf, mono_icall_sig_long_long_long, mono_llmult_ovf, FALSE);
4758 #endif
4760 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4761 register_opcode_emulation (OP_LSHL, __emul_lshl, mono_icall_sig_long_long_int32, mono_lshl, TRUE);
4762 register_opcode_emulation (OP_LSHR, __emul_lshr, mono_icall_sig_long_long_int32, mono_lshr, TRUE);
4763 register_opcode_emulation (OP_LSHR_UN, __emul_lshr_un, mono_icall_sig_long_long_int32, mono_lshr_un, TRUE);
4764 #endif
4766 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4767 register_opcode_emulation (OP_IDIV, __emul_op_idiv, mono_icall_sig_int32_int32_int32, mono_idiv, FALSE);
4768 register_opcode_emulation (OP_IDIV_UN, __emul_op_idiv_un, mono_icall_sig_int32_int32_int32, mono_idiv_un, FALSE);
4769 register_opcode_emulation (OP_IREM, __emul_op_irem, mono_icall_sig_int32_int32_int32, mono_irem, FALSE);
4770 register_opcode_emulation (OP_IREM_UN, __emul_op_irem_un, mono_icall_sig_int32_int32_int32, mono_irem_un, FALSE);
4771 #endif
4773 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4774 register_opcode_emulation (OP_IMUL, __emul_op_imul, mono_icall_sig_int32_int32_int32, mono_imul, TRUE);
4775 #endif
4777 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4778 register_opcode_emulation (OP_IMUL_OVF, __emul_op_imul_ovf, mono_icall_sig_int32_int32_int32, mono_imul_ovf, FALSE);
4779 register_opcode_emulation (OP_IMUL_OVF_UN, __emul_op_imul_ovf_un, mono_icall_sig_int32_int32_int32, mono_imul_ovf_un, FALSE);
4780 #endif
4782 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4783 register_opcode_emulation (OP_FDIV, __emul_fdiv, mono_icall_sig_double_double_double, mono_fdiv, FALSE);
4784 #endif
4786 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4787 register_opcode_emulation (OP_FCONV_TO_U8, __emul_fconv_to_u8, mono_icall_sig_ulong_double, mono_fconv_u8_2, FALSE);
4788 register_opcode_emulation (OP_RCONV_TO_U8, __emul_rconv_to_u8, mono_icall_sig_ulong_float, mono_rconv_u8, FALSE);
4789 #endif
4790 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4791 register_opcode_emulation (OP_FCONV_TO_U4, __emul_fconv_to_u4, mono_icall_sig_uint32_double, mono_fconv_u4_2, FALSE);
4792 register_opcode_emulation (OP_RCONV_TO_U4, __emul_rconv_to_u4, mono_icall_sig_uint32_float, mono_rconv_u4, FALSE);
4793 #endif
4794 register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, FALSE);
4795 register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
4796 register_opcode_emulation (OP_RCONV_TO_OVF_I8, __emul_rconv_to_ovf_i8, mono_icall_sig_long_float, mono_rconv_ovf_i8, FALSE);
4797 register_opcode_emulation (OP_RCONV_TO_OVF_U8, __emul_rconv_to_ovf_u8, mono_icall_sig_ulong_float, mono_rconv_ovf_u8, FALSE);
4799 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4800 register_opcode_emulation (OP_FCONV_TO_I8, __emul_fconv_to_i8, mono_icall_sig_long_double, mono_fconv_i8, FALSE);
4801 register_opcode_emulation (OP_RCONV_TO_I8, __emul_rconv_to_i8, mono_icall_sig_long_float, mono_rconv_i8, FALSE);
4802 #endif
4804 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4805 register_opcode_emulation (OP_ICONV_TO_R_UN, __emul_iconv_to_r_un, mono_icall_sig_double_int32, mono_conv_to_r8_un, FALSE);
4806 #endif
4807 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4808 register_opcode_emulation (OP_LCONV_TO_R8, __emul_lconv_to_r8, mono_icall_sig_double_long, mono_lconv_to_r8, FALSE);
4809 #endif
4810 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4811 register_opcode_emulation (OP_LCONV_TO_R4, __emul_lconv_to_r4, mono_icall_sig_float_long, mono_lconv_to_r4, FALSE);
4812 #endif
4813 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4814 register_opcode_emulation (OP_LCONV_TO_R_UN, __emul_lconv_to_r8_un, mono_icall_sig_double_long, mono_lconv_to_r8_un, FALSE);
4815 #endif
4816 #ifdef MONO_ARCH_EMULATE_FREM
4817 register_opcode_emulation (OP_FREM, __emul_frem, mono_icall_sig_double_double_double, mono_fmod, FALSE);
4818 register_opcode_emulation (OP_RREM, __emul_rrem, mono_icall_sig_float_float_float, fmodf, FALSE);
4819 #endif
4821 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4822 if (mono_arch_is_soft_float ()) {
4823 register_opcode_emulation (OP_FSUB, __emul_fsub, mono_icall_sig_double_double_double, mono_fsub, FALSE);
4824 register_opcode_emulation (OP_FADD, __emul_fadd, mono_icall_sig_double_double_double, mono_fadd, FALSE);
4825 register_opcode_emulation (OP_FMUL, __emul_fmul, mono_icall_sig_double_double_double, mono_fmul, FALSE);
4826 register_opcode_emulation (OP_FNEG, __emul_fneg, mono_icall_sig_double_double, mono_fneg, FALSE);
4827 register_opcode_emulation (OP_ICONV_TO_R8, __emul_iconv_to_r8, mono_icall_sig_double_int32, mono_conv_to_r8, FALSE);
4828 register_opcode_emulation (OP_ICONV_TO_R4, __emul_iconv_to_r4, mono_icall_sig_double_int32, mono_conv_to_r4, FALSE);
4829 register_opcode_emulation (OP_FCONV_TO_R4, __emul_fconv_to_r4, mono_icall_sig_double_double, mono_fconv_r4, FALSE);
4830 register_opcode_emulation (OP_FCONV_TO_I1, __emul_fconv_to_i1, mono_icall_sig_int8_double, mono_fconv_i1, FALSE);
4831 register_opcode_emulation (OP_FCONV_TO_I2, __emul_fconv_to_i2, mono_icall_sig_int16_double, mono_fconv_i2, FALSE);
4832 register_opcode_emulation (OP_FCONV_TO_I4, __emul_fconv_to_i4, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4833 register_opcode_emulation (OP_FCONV_TO_U1, __emul_fconv_to_u1, mono_icall_sig_uint8_double, mono_fconv_u1, FALSE);
4834 register_opcode_emulation (OP_FCONV_TO_U2, __emul_fconv_to_u2, mono_icall_sig_uint16_double, mono_fconv_u2, FALSE);
4836 #if TARGET_SIZEOF_VOID_P == 4
4837 register_opcode_emulation (OP_FCONV_TO_I, __emul_fconv_to_i, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4838 #endif
4840 register_opcode_emulation (OP_FBEQ, __emul_fcmp_eq, mono_icall_sig_uint32_double_double, mono_fcmp_eq, FALSE);
4841 register_opcode_emulation (OP_FBLT, __emul_fcmp_lt, mono_icall_sig_uint32_double_double, mono_fcmp_lt, FALSE);
4842 register_opcode_emulation (OP_FBGT, __emul_fcmp_gt, mono_icall_sig_uint32_double_double, mono_fcmp_gt, FALSE);
4843 register_opcode_emulation (OP_FBLE, __emul_fcmp_le, mono_icall_sig_uint32_double_double, mono_fcmp_le, FALSE);
4844 register_opcode_emulation (OP_FBGE, __emul_fcmp_ge, mono_icall_sig_uint32_double_double, mono_fcmp_ge, FALSE);
4845 register_opcode_emulation (OP_FBNE_UN, __emul_fcmp_ne_un, mono_icall_sig_uint32_double_double, mono_fcmp_ne_un, FALSE);
4846 register_opcode_emulation (OP_FBLT_UN, __emul_fcmp_lt_un, mono_icall_sig_uint32_double_double, mono_fcmp_lt_un, FALSE);
4847 register_opcode_emulation (OP_FBGT_UN, __emul_fcmp_gt_un, mono_icall_sig_uint32_double_double, mono_fcmp_gt_un, FALSE);
4848 register_opcode_emulation (OP_FBLE_UN, __emul_fcmp_le_un, mono_icall_sig_uint32_double_double, mono_fcmp_le_un, FALSE);
4849 register_opcode_emulation (OP_FBGE_UN, __emul_fcmp_ge_un, mono_icall_sig_uint32_double_double, mono_fcmp_ge_un, FALSE);
4851 register_opcode_emulation (OP_FCEQ, __emul_fcmp_ceq, mono_icall_sig_uint32_double_double, mono_fceq, FALSE);
4852 register_opcode_emulation (OP_FCGT, __emul_fcmp_cgt, mono_icall_sig_uint32_double_double, mono_fcgt, FALSE);
4853 register_opcode_emulation (OP_FCGT_UN, __emul_fcmp_cgt_un, mono_icall_sig_uint32_double_double, mono_fcgt_un, FALSE);
4854 register_opcode_emulation (OP_FCLT, __emul_fcmp_clt, mono_icall_sig_uint32_double_double, mono_fclt, FALSE);
4855 register_opcode_emulation (OP_FCLT_UN, __emul_fcmp_clt_un, mono_icall_sig_uint32_double_double, mono_fclt_un, FALSE);
4857 register_icall (mono_fload_r4, mono_icall_sig_double_ptr, FALSE);
4858 register_icall (mono_fstore_r4, mono_icall_sig_void_double_ptr, FALSE);
4859 register_icall (mono_fload_r4_arg, mono_icall_sig_uint32_double, FALSE);
4860 register_icall (mono_isfinite_double, mono_icall_sig_int32_double, FALSE);
4862 #endif
4863 register_icall (mono_ckfinite, mono_icall_sig_double_double, FALSE);
4865 #ifdef COMPRESSED_INTERFACE_BITMAP
4866 register_icall (mono_class_interface_match, mono_icall_sig_uint32_ptr_int32, TRUE);
4867 #endif
4869 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4870 #if SIZEOF_REGISTER == 4
4871 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_uint32_double, mono_fconv_u4, TRUE);
4872 #else
4873 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_ulong_double, mono_fconv_u8, TRUE);
4874 #endif
4876 /* other jit icalls */
4877 register_icall (ves_icall_mono_delegate_ctor, mono_icall_sig_void_object_object_ptr, FALSE);
4878 register_icall (ves_icall_mono_delegate_ctor_interp, mono_icall_sig_void_object_object_ptr, FALSE);
4879 register_icall (mono_class_static_field_address,
4880 mono_icall_sig_ptr_ptr_ptr, FALSE);
4881 register_icall (mono_ldtoken_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4882 register_icall (mono_ldtoken_wrapper_generic_shared,
4883 mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4884 register_icall (mono_get_special_static_data, mono_icall_sig_ptr_int, FALSE);
4885 register_icall (ves_icall_mono_ldstr, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4886 register_icall (mono_helper_stelem_ref_check, mono_icall_sig_void_object_object, FALSE);
4887 register_icall (ves_icall_object_new, mono_icall_sig_object_ptr_ptr, FALSE);
4888 register_icall (ves_icall_object_new_specific, mono_icall_sig_object_ptr, FALSE);
4889 register_icall (ves_icall_array_new, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4890 register_icall (ves_icall_array_new_specific, mono_icall_sig_object_ptr_int32, FALSE);
4891 register_icall (ves_icall_runtime_class_init, mono_icall_sig_void_ptr, FALSE);
4892 register_icall (mono_ldftn, mono_icall_sig_ptr_ptr, FALSE);
4893 register_icall (mono_ldvirtfn, mono_icall_sig_ptr_object_ptr, FALSE);
4894 register_icall (mono_ldvirtfn_gshared, mono_icall_sig_ptr_object_ptr, FALSE);
4895 register_icall (mono_helper_compile_generic_method, mono_icall_sig_ptr_object_ptr_ptr, FALSE);
4896 register_icall (mono_helper_ldstr, mono_icall_sig_object_ptr_int, FALSE);
4897 register_icall (mono_helper_ldstr_mscorlib, mono_icall_sig_object_int, FALSE);
4898 register_icall (mono_helper_newobj_mscorlib, mono_icall_sig_object_int, FALSE);
4899 register_icall (mono_value_copy_internal, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
4900 register_icall (mono_object_castclass_unbox, mono_icall_sig_object_object_ptr, FALSE);
4901 register_icall (mono_break, NULL, TRUE);
4902 register_icall (mono_create_corlib_exception_0, mono_icall_sig_object_int, TRUE);
4903 register_icall (mono_create_corlib_exception_1, mono_icall_sig_object_int_object, TRUE);
4904 register_icall (mono_create_corlib_exception_2, mono_icall_sig_object_int_object_object, TRUE);
4905 register_icall (mono_array_new_1, mono_icall_sig_object_ptr_int, FALSE);
4906 register_icall (mono_array_new_2, mono_icall_sig_object_ptr_int_int, FALSE);
4907 register_icall (mono_array_new_3, mono_icall_sig_object_ptr_int_int_int, FALSE);
4908 register_icall (mono_array_new_4, mono_icall_sig_object_ptr_int_int_int_int, FALSE);
4909 register_icall (mono_array_new_n_icall, mono_icall_sig_object_ptr_int_ptr, FALSE);
4910 register_icall (mono_get_native_calli_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4911 register_icall (mono_resume_unwind, mono_icall_sig_void_ptr, TRUE);
4912 register_icall (mono_gsharedvt_constrained_call, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr, FALSE);
4913 register_icall (mono_gsharedvt_value_copy, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4915 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4916 MonoRangeCopyFunction const mono_gc_wbarrier_range_copy = mono_gc_get_range_copy_func ();
4917 register_icall_no_wrapper (mono_gc_wbarrier_range_copy, mono_icall_sig_void_ptr_ptr_int);
4919 register_icall (mono_object_castclass_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4920 register_icall (mono_object_isinst_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4921 register_icall (mono_generic_class_init, mono_icall_sig_void_ptr, FALSE);
4922 register_icall (mono_fill_class_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4923 register_icall (mono_fill_method_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4925 register_dyn_icall (mini_get_dbg_callbacks ()->user_break, mono_debugger_agent_user_break, mono_icall_sig_void, FALSE);
4927 register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_ptr_ptr_ptr, TRUE);
4928 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4929 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4930 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call, mono_icall_sig_ptr_ptr_int_ptr);
4931 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call, mono_icall_sig_ptr_ptr_int_ptr);
4932 /* This needs a wrapper so it can have a preserveall cconv */
4933 register_icall (mini_llvmonly_init_vtable_slot, mono_icall_sig_ptr_ptr_int, FALSE);
4934 register_icall (mini_llvmonly_init_delegate, mono_icall_sig_void_object, TRUE);
4935 register_icall (mini_llvmonly_init_delegate_virtual, mono_icall_sig_void_object_object_ptr, TRUE);
4936 register_icall (mini_llvmonly_throw_nullref_exception, mono_icall_sig_void, TRUE);
4937 register_icall (mini_llvmonly_throw_aot_failed_exception, mono_icall_sig_void_ptr, TRUE);
4938 register_icall (mini_llvmonly_pop_lmf, mono_icall_sig_void_ptr, TRUE);
4939 register_icall (mini_llvmonly_get_interp_entry, mono_icall_sig_ptr_ptr, TRUE);
4941 register_icall (mono_get_assembly_object, mono_icall_sig_object_ptr, TRUE);
4942 register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE);
4943 register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE);
4944 register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE);
4945 register_icall (mono_throw_not_supported, mono_icall_sig_void, FALSE);
4946 register_icall (mono_throw_invalid_program, mono_icall_sig_void_ptr, FALSE);
4947 register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void);
4949 register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);
4950 register_icall_with_wrapper (mono_monitor_enter_v4_internal, mono_icall_sig_void_obj_ptr);
4951 register_icall_no_wrapper (mono_monitor_enter_fast, mono_icall_sig_int_obj);
4952 register_icall_no_wrapper (mono_monitor_enter_v4_fast, mono_icall_sig_int_obj_ptr);
4954 #ifdef TARGET_IOS
4955 register_icall (pthread_getspecific, mono_icall_sig_ptr_ptr, TRUE);
4956 #endif
4957 /* Register tls icalls */
4958 register_icall_no_wrapper (mono_tls_get_thread_extern, mono_icall_sig_ptr);
4959 register_icall_no_wrapper (mono_tls_get_jit_tls_extern, mono_icall_sig_ptr);
4960 register_icall_no_wrapper (mono_tls_get_domain_extern, mono_icall_sig_ptr);
4961 register_icall_no_wrapper (mono_tls_get_sgen_thread_info_extern, mono_icall_sig_ptr);
4962 register_icall_no_wrapper (mono_tls_get_lmf_addr_extern, mono_icall_sig_ptr);
4964 register_icall_no_wrapper (mono_interp_entry_from_trampoline, mono_icall_sig_void_ptr_ptr);
4965 register_icall_no_wrapper (mono_interp_to_native_trampoline, mono_icall_sig_void_ptr_ptr);
4967 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4968 mono_arch_register_icall ();
4969 #endif
4972 MonoJitStats mono_jit_stats = {0};
4975 * Counters of mono_stats and mono_jit_stats can be read without locking during shutdown.
4976 * For all other contexts, assumes that the domain lock is held.
4977 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4979 MONO_NO_SANITIZE_THREAD
4980 void
4981 mono_runtime_print_stats (void)
4983 if (mono_jit_stats.enabled) {
4984 g_print ("Mono Jit statistics\n");
4985 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4986 mono_jit_stats.max_ratio_method);
4987 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4988 mono_jit_stats.biggest_method);
4990 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4991 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4992 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4993 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4994 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4995 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4996 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4997 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4999 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
5000 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
5001 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
5003 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
5004 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
5005 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
5006 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
5008 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
5009 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
5010 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
5011 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
5012 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
5013 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
5014 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
5015 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
5017 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
5018 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
5019 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
5021 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, NULL);
5022 g_print ("\n");
5026 static void
5027 jit_stats_cleanup (void)
5029 g_free (mono_jit_stats.max_ratio_method);
5030 mono_jit_stats.max_ratio_method = NULL;
5031 g_free (mono_jit_stats.biggest_method);
5032 mono_jit_stats.biggest_method = NULL;
5035 static void
5036 runtime_cleanup (MonoDomain *domain, gpointer user_data)
5038 mini_cleanup (domain);
5041 #ifdef DISABLE_CLEANUP
5042 void
5043 mini_cleanup (MonoDomain *domain)
5045 if (mono_stats.enabled)
5046 g_printf ("Printing runtime stats at shutdown\n");
5047 mono_runtime_print_stats ();
5048 jit_stats_cleanup ();
5049 mono_jit_dump_cleanup ();
5050 mini_get_interp_callbacks ()->cleanup ();
5051 #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE)
5052 ep_shutdown ();
5053 ds_server_shutdown ();
5054 #endif
5056 #else
5057 void
5058 mini_cleanup (MonoDomain *domain)
5060 if (mono_stats.enabled)
5061 g_printf ("Printing runtime stats at shutdown\n");
5062 if (mono_profiler_sampling_enabled ())
5063 mono_runtime_shutdown_stat_profiler ();
5065 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
5067 #ifndef DISABLE_COM
5068 mono_cominterop_release_all_rcws ();
5069 #endif
5071 #ifndef MONO_CROSS_COMPILE
5073 * mono_domain_finalize () needs to be called early since it needs the
5074 * execution engine still fully working (it may invoke managed finalizers).
5076 mono_domain_finalize (domain, 2000);
5077 #endif
5079 /* This accesses metadata so needs to be called before runtime shutdown */
5080 mono_runtime_print_stats ();
5081 jit_stats_cleanup ();
5083 #ifndef MONO_CROSS_COMPILE
5084 mono_runtime_cleanup (domain);
5085 #endif
5087 mono_threadpool_cleanup ();
5089 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
5091 mono_profiler_cleanup ();
5093 if (profile_options) {
5094 for (guint i = 0; i < profile_options->len; ++i)
5095 g_free (g_ptr_array_index (profile_options, i));
5096 g_ptr_array_free (profile_options, TRUE);
5099 mono_icall_cleanup ();
5101 mono_runtime_cleanup_handlers ();
5103 #ifndef MONO_CROSS_COMPILE
5104 mono_domain_free (domain, TRUE);
5105 #endif
5106 free_jit_tls_data (mono_tls_get_jit_tls ());
5108 #ifdef ENABLE_LLVM
5109 if (mono_use_llvm)
5110 mono_llvm_cleanup ();
5111 #endif
5113 mono_aot_cleanup ();
5115 mono_trampolines_cleanup ();
5117 mono_unwind_cleanup ();
5119 mono_code_manager_destroy (global_codeman);
5120 g_free (vtable_trampolines);
5122 mini_jit_cleanup ();
5124 mini_get_interp_callbacks ()->cleanup ();
5126 mono_tramp_info_cleanup ();
5128 mono_arch_cleanup ();
5130 mono_generic_sharing_cleanup ();
5132 mono_cleanup_native_crash_info ();
5134 mono_cleanup ();
5136 mono_trace_cleanup ();
5138 if (mono_inject_async_exc_method)
5139 mono_method_desc_free (mono_inject_async_exc_method);
5141 mono_tls_free_keys ();
5143 mono_os_mutex_destroy (&jit_mutex);
5145 mono_code_manager_cleanup ();
5147 #ifndef HOST_WIN32
5148 mono_w32handle_cleanup ();
5149 #endif
5151 #endif
5153 void
5154 mono_set_defaults (int verbose_level, guint32 opts)
5156 mini_verbose = verbose_level;
5157 mono_set_optimizations (opts);
5160 void
5161 mono_disable_optimizations (guint32 opts)
5163 default_opt &= ~opts;
5166 void
5167 mono_set_optimizations (guint32 opts)
5169 if (opts & MONO_OPT_AGGRESSIVE_INLINING)
5170 opts |= MONO_OPT_INLINE;
5172 default_opt = opts;
5173 default_opt_set = TRUE;
5174 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
5175 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
5176 #else
5177 if (mono_llvm_only)
5178 mono_set_generic_sharing_vt_supported (TRUE);
5179 #endif
5182 void
5183 mono_set_verbose_level (guint32 level)
5185 mini_verbose = level;
5188 static const char*
5189 mono_get_runtime_build_version (void)
5191 return FULL_VERSION;
5195 * mono_get_runtime_build_info:
5196 * The returned string is owned by the caller. The returned string
5197 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
5198 * \returns the runtime version + build date in string format.
5200 char*
5201 mono_get_runtime_build_info (void)
5203 if (mono_build_date)
5204 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
5205 else
5206 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
5209 static void
5210 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
5212 GHashTable *assemblies = (GHashTable*)user_data;
5213 MonoImage *image = mono_assembly_get_image_internal (ass);
5214 MonoMethod *method, *invoke;
5215 int i, count = 0;
5217 if (g_hash_table_lookup (assemblies, ass))
5218 return;
5220 g_hash_table_insert (assemblies, ass, ass);
5222 if (mini_verbose > 0)
5223 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
5225 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5226 ERROR_DECL (error);
5228 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
5229 if (!method) {
5230 mono_error_cleanup (error); /* FIXME don't swallow the error */
5231 continue;
5233 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
5234 continue;
5235 if (method->is_generic || mono_class_is_gtd (method->klass))
5236 continue;
5238 count++;
5239 if (mini_verbose > 1) {
5240 char * desc = mono_method_full_name (method, TRUE);
5241 g_print ("Compiling %d %s\n", count, desc);
5242 g_free (desc);
5244 mono_compile_method_checked (method, error);
5245 if (!is_ok (error)) {
5246 mono_error_cleanup (error); /* FIXME don't swallow the error */
5247 continue;
5249 if (strcmp (method->name, "Finalize") == 0) {
5250 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
5251 mono_compile_method_checked (invoke, error);
5252 mono_error_assert_ok (error);
5254 #ifndef DISABLE_REMOTING
5255 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
5256 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
5257 mono_error_assert_ok (error);
5258 mono_compile_method_checked (invoke, error);
5259 mono_error_assert_ok (error);
5261 #endif
5264 /* Load and precompile referenced assemblies as well */
5265 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
5266 mono_assembly_load_reference (image, i);
5267 if (image->references [i])
5268 mono_precompile_assembly (image->references [i], assemblies);
5272 void mono_precompile_assemblies ()
5274 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
5276 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
5278 g_hash_table_destroy (assemblies);
5282 * Used by LLVM.
5283 * Have to export this for AOT.
5285 void
5286 mono_personality (void)
5288 /* Not used */
5289 g_assert_not_reached ();
5292 static MonoBreakPolicy
5293 always_insert_breakpoint (MonoMethod *method)
5295 return MONO_BREAK_POLICY_ALWAYS;
5298 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5301 * mono_set_break_policy:
5302 * \param policy_callback the new callback function
5304 * Allow embedders to decide whether to actually obey breakpoint instructions
5305 * (both break IL instructions and \c Debugger.Break method calls), for example
5306 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5307 * untrusted or semi-trusted code.
5309 * \p policy_callback will be called every time a break point instruction needs to
5310 * be inserted with the method argument being the method that calls \c Debugger.Break
5311 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5312 * if it wants the breakpoint to not be effective in the given method.
5313 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5315 void
5316 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5318 if (policy_callback)
5319 break_policy_func = policy_callback;
5320 else
5321 break_policy_func = always_insert_breakpoint;
5324 gboolean
5325 mini_should_insert_breakpoint (MonoMethod *method)
5327 switch (break_policy_func (method)) {
5328 case MONO_BREAK_POLICY_ALWAYS:
5329 return TRUE;
5330 case MONO_BREAK_POLICY_NEVER:
5331 return FALSE;
5332 case MONO_BREAK_POLICY_ON_DBG:
5333 g_warning ("mdb no longer supported");
5334 return FALSE;
5335 default:
5336 g_warning ("Incorrect value returned from break policy callback");
5337 return FALSE;
5341 // Custom handlers currently only implemented by Windows.
5342 #ifndef HOST_WIN32
5343 gboolean
5344 mono_runtime_install_custom_handlers (const char *handlers)
5346 return FALSE;
5349 void
5350 mono_runtime_install_custom_handlers_usage (void)
5352 fprintf (stdout,
5353 "Custom Handlers:\n"
5354 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5355 " separated list of available handlers to install.\n"
5356 "\n"
5357 "No handlers supported on current platform.\n");
5359 #endif /* HOST_WIN32 */
5361 #ifdef ENABLE_METADATA_UPDATE
5362 void
5363 mini_metadata_update_init (MonoError *error)
5365 mini_get_interp_callbacks ()->metadata_update_init (error);
5368 void
5369 mini_invalidate_transformed_interp_methods (MonoDomain *domain, MonoAssemblyLoadContext *alc G_GNUC_UNUSED, uint32_t generation G_GNUC_UNUSED)
5371 mini_get_interp_callbacks ()->invalidate_transformed (domain);
5373 #endif