[interp] Fix interp logging (#17636)
[mono-project.git] / mono / mini / mini-runtime.c
blob459b9b89bddb732cb3cfda5dbb3f466047340015
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/metadata/w32handle.h>
74 #include <mono/metadata/threadpool.h>
76 #include "mini.h"
77 #include "seq-points.h"
78 #include "tasklets.h"
79 #include <string.h>
80 #include <ctype.h>
81 #include "trace.h"
82 #include "version.h"
83 #include "aot-compiler.h"
84 #include "aot-runtime.h"
85 #include "llvmonly-runtime.h"
87 #include "jit-icalls.h"
89 #include "mini-gc.h"
90 #include "mini-llvm.h"
91 #include "debugger-agent.h"
92 #include "lldb.h"
93 #include "mini-runtime.h"
94 #include "interp/interp.h"
96 #ifdef MONO_ARCH_LLVM_SUPPORTED
97 #ifdef ENABLE_LLVM
98 #include "mini-llvm-cpp.h"
99 #include "llvm-jit.h"
100 #endif
101 #endif
102 #include "mono/metadata/icall-signatures.h"
103 #include "mono/utils/mono-tls-inline.h"
105 static guint32 default_opt = 0;
106 static gboolean default_opt_set = FALSE;
108 gboolean mono_compile_aot = FALSE;
109 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
110 gboolean mono_aot_only = FALSE;
111 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
112 gboolean mono_llvm_only = FALSE;
113 /* By default, don't require AOT but attempt to probe */
114 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NORMAL;
115 MonoEEFeatures mono_ee_features;
117 const char *mono_build_date;
118 gboolean mono_do_signal_chaining;
119 gboolean mono_do_crash_chaining;
120 int mini_verbose = 0;
123 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
124 * it can load AOT code compiled by LLVM.
126 gboolean mono_use_llvm = FALSE;
128 gboolean mono_use_fast_math = FALSE;
130 // Lists of whitelisted and blacklisted CPU features
131 MonoCPUFeatures mono_cpu_features_enabled = (MonoCPUFeatures)0;
132 MonoCPUFeatures mono_cpu_features_disabled = (MonoCPUFeatures)0;
134 gboolean mono_use_interpreter = FALSE;
135 const char *mono_interp_opts_string = NULL;
137 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
138 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
139 static mono_mutex_t jit_mutex;
141 static MonoCodeManager *global_codeman;
143 MonoDebugOptions mini_debug_options;
144 char *sdb_options;
146 #ifdef VALGRIND_JIT_REGISTER_MAP
147 int valgrind_register;
148 #endif
149 GList* mono_aot_paths;
151 static GPtrArray *profile_options;
153 static GSList *tramp_infos;
154 GSList *mono_interp_only_classes;
156 static void register_icalls (void);
158 gboolean
159 mono_running_on_valgrind (void)
161 #ifndef HOST_WIN32
162 if (RUNNING_ON_VALGRIND){
163 #ifdef VALGRIND_JIT_REGISTER_MAP
164 valgrind_register = TRUE;
165 #endif
166 return TRUE;
167 } else
168 #endif
169 return FALSE;
172 void
173 mono_set_use_llvm (mono_bool use_llvm)
175 mono_use_llvm = (gboolean)use_llvm;
179 typedef struct {
180 void *ip;
181 MonoMethod *method;
182 } FindTrampUserData;
184 static void
185 find_tramp (gpointer key, gpointer value, gpointer user_data)
187 FindTrampUserData *ud = (FindTrampUserData*)user_data;
189 if (value == ud->ip)
190 ud->method = (MonoMethod*)key;
193 /* debug function */
194 char*
195 mono_get_method_from_ip (void *ip)
197 MonoJitInfo *ji;
198 MonoMethod *method;
199 char *method_name;
200 char *res;
201 MonoDomain *domain = mono_domain_get ();
202 MonoDebugSourceLocation *location;
203 FindTrampUserData user_data;
205 if (!domain)
206 domain = mono_get_root_domain ();
208 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
209 if (!ji) {
210 user_data.ip = ip;
211 user_data.method = NULL;
212 mono_domain_lock (domain);
213 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
214 mono_domain_unlock (domain);
215 if (user_data.method) {
216 char *mname = mono_method_full_name (user_data.method, TRUE);
217 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
218 g_free (mname);
219 return res;
221 else
222 return NULL;
223 } else if (ji->is_trampoline) {
224 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
225 return res;
228 method = jinfo_get_method (ji);
229 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
230 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
232 char *file_loc = NULL;
233 if (location)
234 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
236 const char *in_interp = ji->is_interp ? " interp" : "";
238 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);
240 mono_debug_free_source_location (location);
241 g_free (method_name);
242 g_free (file_loc);
244 return res;
248 * mono_pmip:
249 * \param ip an instruction pointer address
251 * This method is used from a debugger to get the name of the
252 * method at address \p ip. This routine is typically invoked from
253 * a debugger like this:
255 * (gdb) print mono_pmip ($pc)
257 * \returns the name of the method at address \p ip.
259 G_GNUC_UNUSED char *
260 mono_pmip (void *ip)
262 return mono_get_method_from_ip (ip);
266 * mono_print_method_from_ip:
267 * \param ip an instruction pointer address
269 * This method is used from a debugger to get the name of the
270 * method at address \p ip.
272 * This prints the name of the method at address \p ip in the standard
273 * output. Unlike \c mono_pmip which returns a string, this routine
274 * prints the value on the standard output.
276 MONO_ATTR_USED void
277 mono_print_method_from_ip (void *ip)
279 MonoJitInfo *ji;
280 char *method;
281 MonoDebugSourceLocation *source;
282 MonoDomain *domain = mono_domain_get ();
283 MonoDomain *target_domain = mono_domain_get ();
284 FindTrampUserData user_data;
285 MonoGenericSharingContext*gsctx;
286 const char *shared_type;
288 if (!domain)
289 domain = mono_get_root_domain ();
290 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
291 if (ji && ji->is_trampoline) {
292 MonoTrampInfo *tinfo = ji->d.tramp_info;
294 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
295 return;
298 if (!ji) {
299 user_data.ip = ip;
300 user_data.method = NULL;
301 mono_domain_lock (domain);
302 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
303 mono_domain_unlock (domain);
305 if (user_data.method) {
306 char *mname = mono_method_full_name (user_data.method, TRUE);
307 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
308 g_free (mname);
309 return;
312 g_print ("No method at %p\n", ip);
313 fflush (stdout);
314 return;
316 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
317 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
319 gsctx = mono_jit_info_get_generic_sharing_context (ji);
320 shared_type = "";
321 if (gsctx) {
322 if (gsctx->is_gsharedvt)
323 shared_type = "gsharedvt ";
324 else
325 shared_type = "gshared ";
328 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);
330 if (source)
331 g_print ("%s:%d\n", source->source_file, source->row);
332 fflush (stdout);
334 mono_debug_free_source_location (source);
335 g_free (method);
339 * mono_method_same_domain:
341 * Determine whenever two compiled methods are in the same domain, thus
342 * the address of the callee can be embedded in the caller.
344 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
346 MonoMethod *cmethod;
348 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
349 return FALSE;
352 * If the call was made from domain-neutral to domain-specific
353 * code, we can't patch the call site.
355 if (caller->domain_neutral && !callee->domain_neutral)
356 return FALSE;
358 cmethod = jinfo_get_method (caller);
359 if ((cmethod->klass == mono_defaults.appdomain_class) &&
360 (strstr (cmethod->name, "InvokeInDomain"))) {
361 /* The InvokeInDomain methods change the current appdomain */
362 return FALSE;
365 return TRUE;
369 * mono_global_codeman_reserve:
371 * Allocate code memory from the global code manager.
373 void *(mono_global_codeman_reserve) (int size)
375 void *ptr;
377 if (mono_aot_only)
378 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
380 if (!global_codeman) {
381 /* This can happen during startup */
382 global_codeman = mono_code_manager_new ();
383 return mono_code_manager_reserve (global_codeman, size);
385 else {
386 mono_jit_lock ();
387 ptr = mono_code_manager_reserve (global_codeman, size);
388 mono_jit_unlock ();
389 return ptr;
393 /* The callback shouldn't take any locks */
394 void
395 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
397 mono_jit_lock ();
398 mono_code_manager_foreach (global_codeman, func, user_data);
399 mono_jit_unlock ();
403 * mono_create_unwind_op:
405 * Create an unwind op with the given parameters.
407 MonoUnwindOp*
408 mono_create_unwind_op (int when, int tag, int reg, int val)
410 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
412 op->op = tag;
413 op->reg = reg;
414 op->val = val;
415 op->when = when;
417 return op;
420 MonoJumpInfoToken *
421 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
423 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
424 res->image = image;
425 res->token = token;
426 res->has_context = context != NULL;
427 if (context)
428 memcpy (&res->context, context, sizeof (MonoGenericContext));
430 return res;
433 MonoJumpInfoToken *
434 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
436 return mono_jump_info_token_new2 (mp, image, token, NULL);
440 * mono_tramp_info_create:
442 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
443 * of JI, and UNWIND_OPS.
445 MonoTrampInfo*
446 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
448 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
450 info->name = g_strdup (name);
451 info->code = code;
452 info->code_size = code_size;
453 info->ji = ji;
454 info->unwind_ops = unwind_ops;
456 return info;
459 void
460 mono_tramp_info_free (MonoTrampInfo *info)
462 g_free (info->name);
464 // FIXME: ji
465 mono_free_unwind_info (info->unwind_ops);
466 if (info->owns_uw_info)
467 g_free (info->uw_info);
468 g_free (info);
471 static void
472 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
474 MonoJitInfo *ji;
476 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
477 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
478 ji->d.tramp_info = info;
479 ji->is_trampoline = TRUE;
481 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
483 mono_jit_info_table_add (domain, ji);
487 * mono_tramp_info_register:
489 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
490 * INFO can be NULL.
491 * Frees INFO.
493 static void
494 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
496 MonoTrampInfo *copy;
498 if (!info)
499 return;
501 if (!domain)
502 domain = mono_get_root_domain ();
504 if (domain)
505 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
506 else
507 copy = g_new0 (MonoTrampInfo, 1);
509 copy->code = info->code;
510 copy->code_size = info->code_size;
511 copy->name = g_strdup (info->name);
513 if (info->unwind_ops) {
514 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
515 copy->owns_uw_info = TRUE;
516 if (domain) {
517 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
518 guint8 *temp = copy->uw_info;
519 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
520 memcpy (copy->uw_info, temp, copy->uw_info_len);
521 g_free (temp);
523 } else {
524 /* Trampolines from aot have the unwind ops already encoded */
525 copy->uw_info = info->uw_info;
526 copy->uw_info_len = info->uw_info_len;
529 mono_save_trampoline_xdebug_info (info);
530 mono_lldb_save_trampoline_info (info);
532 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
533 if (!aot)
534 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
535 #endif
537 if (!domain) {
538 /* If no root domain has been created yet, postpone the registration. */
539 mono_jit_lock ();
540 tramp_infos = g_slist_prepend (tramp_infos, copy);
541 mono_jit_unlock ();
542 } else if (copy->uw_info) {
543 /* Only register trampolines that have unwind infos */
544 register_trampoline_jit_info (domain, copy);
547 if (mono_jit_map_is_enabled ())
548 mono_emit_jit_tramp (info->code, info->code_size, info->name);
550 mono_tramp_info_free (info);
553 void
554 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
556 mono_tramp_info_register_internal (info, domain, FALSE);
559 void
560 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
562 mono_tramp_info_register_internal (info, domain, TRUE);
565 static void
566 mono_tramp_info_cleanup (void)
568 GSList *l;
570 for (l = tramp_infos; l; l = l->next) {
571 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
573 mono_tramp_info_free (info);
575 g_slist_free (tramp_infos);
578 /* Register trampolines created before the root domain was created in the jit info tables */
579 static void
580 register_trampolines (MonoDomain *domain)
582 GSList *l;
584 for (l = tramp_infos; l; l = l->next) {
585 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
587 register_trampoline_jit_info (domain, info);
591 G_GNUC_UNUSED static void
592 break_count (void)
597 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
598 * Set a breakpoint in break_count () to break the last time <x> is done.
600 G_GNUC_UNUSED gboolean
601 mono_debug_count (void)
603 static int count = 0, int_val = 0;
604 static gboolean inited, has_value = FALSE;
606 count ++;
608 if (!inited) {
609 char *value = g_getenv ("COUNT");
610 if (value) {
611 int_val = atoi (value);
612 g_free (value);
613 has_value = TRUE;
615 inited = TRUE;
618 if (!has_value)
619 return TRUE;
621 if (count == int_val)
622 break_count ();
624 if (count > int_val)
625 return FALSE;
627 return TRUE;
630 MonoMethod*
631 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
633 /* This icall is used to check for exceptions, so don't check in the wrapper */
634 gboolean check_exc = (callinfo != &mono_get_jit_icall_info ()->mono_thread_interruption_checkpoint);
636 return mono_marshal_get_icall_wrapper (callinfo, check_exc);
639 gconstpointer
640 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
642 ERROR_DECL (error);
643 MonoMethod *wrapper;
644 gconstpointer addr, trampoline;
645 MonoDomain *domain = mono_get_root_domain ();
647 if (callinfo->wrapper)
648 return callinfo->wrapper;
650 wrapper = mono_icall_get_wrapper_method (callinfo);
652 if (do_compile) {
653 addr = mono_compile_method_checked (wrapper, error);
654 mono_error_assert_ok (error);
655 mono_memory_barrier ();
656 callinfo->wrapper = addr;
657 return addr;
658 } else {
659 if (callinfo->trampoline)
660 return callinfo->trampoline;
661 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
662 mono_error_assert_ok (error);
663 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
665 mono_loader_lock ();
666 if (!callinfo->trampoline) {
667 callinfo->trampoline = trampoline;
669 mono_loader_unlock ();
671 return callinfo->trampoline;
675 gconstpointer
676 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
678 return mono_icall_get_wrapper_full (callinfo, FALSE);
681 static MonoJitDynamicMethodInfo*
682 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
684 MonoJitDynamicMethodInfo *res;
686 if (domain_jit_info (domain)->dynamic_code_hash)
687 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
688 else
689 res = NULL;
690 return res;
693 #ifdef __cplusplus
694 template <typename T>
695 static void
696 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, T func, const char *symbol, gboolean no_wrapper)
697 #else
698 static void
699 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, gpointer func, const char *symbol, gboolean no_wrapper)
700 #endif
702 #ifndef DISABLE_JIT
703 mini_register_opcode_emulation (opcode, jit_icall_info, name, sig, func, symbol, no_wrapper);
704 #else
705 // FIXME ifdef in mini_register_opcode_emulation and just call it.
707 g_assert (!sig->hasthis);
708 g_assert (sig->param_count < 3);
710 mono_register_jit_icall_info (jit_icall_info, func, name, sig, no_wrapper, symbol);
711 #endif
714 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
715 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
718 * For JIT icalls implemented in C.
719 * NAME should be the same as the name of the C function whose address is FUNC.
720 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
721 * can't throw exceptions.
723 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
724 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
726 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
727 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
728 * must be extern "C".
730 #define register_icall(func, sig, avoid_wrapper) \
731 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
733 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
734 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
737 * Register an icall where FUNC is dynamically generated or otherwise not
738 * possible to link to it using NAME during AOT.
740 * func is an expression, such a local variable or a function call to get a function pointer.
741 * name is an identifier
743 * Providing func and name separately is what distinguishes "dyn" from regular.
745 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
747 #define register_dyn_icall(func, name, sig, save) \
748 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
750 MonoLMF *
751 mono_get_lmf (void)
753 MonoJitTlsData *jit_tls;
755 if ((jit_tls = mono_tls_get_jit_tls ()))
756 return jit_tls->lmf;
758 * We do not assert here because this function can be called from
759 * mini-gc.c on a thread that has not executed any managed code, yet
760 * (the thread object allocation can trigger a collection).
762 return NULL;
765 void
766 mono_set_lmf (MonoLMF *lmf)
768 (*mono_get_lmf_addr ()) = lmf;
771 static void
772 mono_set_jit_tls (MonoJitTlsData *jit_tls)
774 MonoThreadInfo *info;
776 mono_tls_set_jit_tls (jit_tls);
778 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
779 info = mono_thread_info_current ();
780 if (info)
781 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
784 static void
785 mono_set_lmf_addr (MonoLMF **lmf_addr)
787 MonoThreadInfo *info;
789 mono_tls_set_lmf_addr (lmf_addr);
791 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
792 info = mono_thread_info_current ();
793 if (info)
794 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
798 * mono_push_lmf:
800 * Push an MonoLMFExt frame on the LMF stack.
802 void
803 mono_push_lmf (MonoLMFExt *ext)
805 MonoLMF **lmf_addr;
807 lmf_addr = mono_get_lmf_addr ();
809 ext->lmf.previous_lmf = *lmf_addr;
810 /* Mark that this is a MonoLMFExt */
811 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
813 mono_set_lmf ((MonoLMF*)ext);
817 * mono_pop_lmf:
819 * Pop the last frame from the LMF stack.
821 void
822 mono_pop_lmf (MonoLMF *lmf)
824 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
828 * mono_jit_thread_attach:
830 * Called by Xamarin.Mac and other products. Attach thread to runtime if
831 * needed and switch to @domain.
833 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
835 * If the thread is newly-attached, put into GC Safe mode.
837 * @return the original domain which needs to be restored, or NULL.
839 MonoDomain*
840 mono_jit_thread_attach (MonoDomain *domain)
842 MonoDomain *orig;
843 gboolean attached;
845 if (!domain) {
846 /* Happens when called from AOTed code which is only used in the root domain. */
847 domain = mono_get_root_domain ();
850 g_assert (domain);
852 attached = mono_tls_get_jit_tls () != NULL;
854 if (!attached) {
855 mono_thread_attach (domain);
857 // #678164
858 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
860 /* mono_jit_thread_attach is external-only and not called by
861 * the runtime on any of our own threads. So if we get here,
862 * the thread is running native code - leave it in GC Safe mode
863 * and leave it to the n2m invoke wrappers or MONO_API entry
864 * points to switch to GC Unsafe.
866 MONO_STACKDATA (stackdata);
867 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
870 orig = mono_domain_get ();
871 if (orig != domain)
872 mono_domain_set_fast (domain, TRUE);
874 return orig != domain ? orig : NULL;
878 * mono_jit_set_domain:
880 * Set domain to @domain if @domain is not null
882 void
883 mono_jit_set_domain (MonoDomain *domain)
885 g_assert (!mono_threads_is_blocking_transition_enabled ());
887 if (domain)
888 mono_domain_set_fast (domain, TRUE);
892 * mono_thread_abort:
893 * \param obj exception object
894 * Abort the thread, print exception information and stack trace
896 static void
897 mono_thread_abort (MonoObject *obj)
899 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
901 /* handle_remove should be eventually called for this thread, too
902 g_free (jit_tls);*/
904 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
905 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
906 ((obj->vtable->klass) == mono_class_try_get_appdomain_unloaded_exception_class () &&
907 mono_thread_info_current ()->runtime_thread)) {
908 mono_thread_exit ();
909 } else {
910 mono_invoke_unhandled_exception_hook (obj);
914 static MonoJitTlsData*
915 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
917 MonoJitTlsData *jit_tls;
918 MonoLMF *lmf;
920 jit_tls = mono_tls_get_jit_tls ();
921 if (jit_tls)
922 return jit_tls;
924 jit_tls = g_new0 (MonoJitTlsData, 1);
926 jit_tls->abort_func = abort_func;
927 jit_tls->end_of_stack = stack_start;
929 mono_set_jit_tls (jit_tls);
931 lmf = g_new0 (MonoLMF, 1);
932 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
934 jit_tls->first_lmf = lmf;
936 mono_set_lmf_addr (&jit_tls->lmf);
938 jit_tls->lmf = lmf;
940 #ifdef MONO_ARCH_HAVE_TLS_INIT
941 mono_arch_tls_init ();
942 #endif
944 mono_setup_altstack (jit_tls);
946 return jit_tls;
949 static void
950 free_jit_tls_data (MonoJitTlsData *jit_tls)
952 //This happens during AOT cuz the thread is never attached
953 if (!jit_tls)
954 return;
955 mono_free_altstack (jit_tls);
957 if (jit_tls->interp_context)
958 mini_get_interp_callbacks ()->free_context (jit_tls->interp_context);
960 g_free (jit_tls->first_lmf);
961 g_free (jit_tls);
964 static void
965 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
967 MonoThreadInfo *thread;
968 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
969 thread = mono_thread_info_current_unchecked ();
970 if (thread)
971 thread->jit_data = jit_tls;
973 mono_arch_cpu_init ();
976 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
978 static void
979 mono_thread_abort_dummy (MonoObject *obj)
981 if (mono_thread_attach_aborted_cb)
982 mono_thread_attach_aborted_cb (obj);
983 else
984 mono_thread_abort (obj);
987 static void
988 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
990 MonoThreadInfo *thread;
991 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
992 thread = mono_thread_info_current_unchecked ();
993 if (thread)
994 thread->jit_data = jit_tls;
996 mono_arch_cpu_init ();
999 static void
1000 mini_thread_cleanup (MonoNativeThreadId tid)
1002 MonoJitTlsData *jit_tls = NULL;
1003 MonoThreadInfo *info;
1005 info = mono_thread_info_current_unchecked ();
1007 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1008 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1009 * not a trivial thing.
1011 * The current offender is mono_thread_manage which cleanup threads from the outside.
1013 if (info && mono_thread_info_get_tid (info) == tid) {
1014 jit_tls = info->jit_data;
1015 info->jit_data = NULL;
1017 mono_set_jit_tls (NULL);
1019 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1020 if (mono_get_lmf ()) {
1021 mono_set_lmf (NULL);
1022 mono_set_lmf_addr (NULL);
1024 } else {
1025 info = mono_thread_info_lookup (tid);
1026 if (info) {
1027 jit_tls = info->jit_data;
1028 info->jit_data = NULL;
1030 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1033 if (jit_tls)
1034 free_jit_tls_data (jit_tls);
1037 MonoJumpInfo *
1038 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1040 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1042 ji->ip.i = ip;
1043 ji->type = type;
1044 ji->data.target = target;
1045 ji->next = list;
1047 return ji;
1050 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1052 static const char* const patch_info_str[] = {
1053 #define PATCH_INFO(a,b) "" #a,
1054 #include "patch-info.h"
1055 #undef PATCH_INFO
1058 const char*
1059 mono_ji_type_to_string (MonoJumpInfoType type)
1061 return patch_info_str [type];
1064 void
1065 mono_print_ji (const MonoJumpInfo *ji)
1067 const char *type = patch_info_str [ji->type];
1068 switch (ji->type) {
1069 case MONO_PATCH_INFO_RGCTX_FETCH:
1070 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1071 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1073 printf ("[%s ", type);
1074 mono_print_ji (entry->data);
1075 printf (" -> %s]", mono_rgctx_info_type_to_str (entry->info_type));
1076 break;
1078 case MONO_PATCH_INFO_METHOD:
1079 case MONO_PATCH_INFO_METHODCONST:
1080 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1081 char *s = mono_method_get_full_name (ji->data.method);
1082 printf ("[%s %s]", type, s);
1083 g_free (s);
1084 break;
1086 case MONO_PATCH_INFO_JIT_ICALL_ID:
1087 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji->data.jit_icall_id)->name);
1088 break;
1089 case MONO_PATCH_INFO_CLASS:
1090 case MONO_PATCH_INFO_VTABLE: {
1091 char *name = mono_class_full_name (ji->data.klass);
1092 printf ("[%s %s]", type, name);
1093 g_free (name);
1094 break;
1096 default:
1097 printf ("[%s]", type);
1098 break;
1102 #else
1104 const char*
1105 mono_ji_type_to_string (MonoJumpInfoType type)
1107 return "";
1110 void
1111 mono_print_ji (const MonoJumpInfo *ji)
1115 #endif
1118 * mono_patch_info_dup_mp:
1120 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1122 MonoJumpInfo*
1123 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1125 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1126 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1128 switch (patch_info->type) {
1129 case MONO_PATCH_INFO_RVA:
1130 case MONO_PATCH_INFO_LDSTR:
1131 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1132 case MONO_PATCH_INFO_LDTOKEN:
1133 case MONO_PATCH_INFO_DECLSEC:
1134 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1135 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1136 break;
1137 case MONO_PATCH_INFO_SWITCH:
1138 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1139 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1140 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1141 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1142 break;
1143 case MONO_PATCH_INFO_RGCTX_FETCH:
1144 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1145 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1146 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1147 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1148 break;
1149 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1150 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1151 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1152 break;
1153 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1154 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1155 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1156 break;
1157 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1158 MonoGSharedVtMethodInfo *info;
1159 MonoGSharedVtMethodInfo *oinfo;
1160 int i;
1162 oinfo = patch_info->data.gsharedvt_method;
1163 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1164 res->data.gsharedvt_method = info;
1165 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1166 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1167 for (i = 0; i < oinfo->num_entries; ++i) {
1168 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1169 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1171 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1173 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1174 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1175 break;
1177 case MONO_PATCH_INFO_VIRT_METHOD: {
1178 MonoJumpInfoVirtMethod *info;
1179 MonoJumpInfoVirtMethod *oinfo;
1181 oinfo = patch_info->data.virt_method;
1182 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1183 res->data.virt_method = info;
1184 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1185 break;
1187 default:
1188 break;
1191 return res;
1194 guint
1195 mono_patch_info_hash (gconstpointer data)
1197 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1198 const MonoJumpInfoType type = ji->type;
1199 guint hash = type << 8;
1201 switch (type) {
1202 case MONO_PATCH_INFO_RVA:
1203 case MONO_PATCH_INFO_LDSTR:
1204 case MONO_PATCH_INFO_LDTOKEN:
1205 case MONO_PATCH_INFO_DECLSEC:
1206 return hash | ji->data.token->token;
1207 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1208 return hash | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1209 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: // Hash on the selector name
1210 case MONO_PATCH_INFO_LDSTR_LIT:
1211 return g_str_hash (ji->data.name);
1212 case MONO_PATCH_INFO_VTABLE:
1213 case MONO_PATCH_INFO_CLASS:
1214 case MONO_PATCH_INFO_IID:
1215 case MONO_PATCH_INFO_ADJUSTED_IID:
1216 case MONO_PATCH_INFO_METHODCONST:
1217 case MONO_PATCH_INFO_METHOD:
1218 case MONO_PATCH_INFO_METHOD_JUMP:
1219 case MONO_PATCH_INFO_METHOD_FTNDESC:
1220 case MONO_PATCH_INFO_IMAGE:
1221 case MONO_PATCH_INFO_ICALL_ADDR:
1222 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1223 case MONO_PATCH_INFO_FIELD:
1224 case MONO_PATCH_INFO_SFLDA:
1225 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1226 case MONO_PATCH_INFO_METHOD_RGCTX:
1227 case MONO_PATCH_INFO_SIGNATURE:
1228 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1229 case MONO_PATCH_INFO_AOT_JIT_INFO:
1230 return hash | (gssize)ji->data.target;
1231 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1232 return hash | (gssize)ji->data.gsharedvt->method;
1233 case MONO_PATCH_INFO_RGCTX_FETCH:
1234 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1235 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1236 hash |= e->in_mrgctx | e->info_type | mono_patch_info_hash (e->data);
1237 if (e->in_mrgctx)
1238 return hash | (gssize)e->d.method;
1239 else
1240 return hash | (gssize)e->d.klass;
1242 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1243 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1244 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1245 case MONO_PATCH_INFO_GC_NURSERY_START:
1246 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1247 case MONO_PATCH_INFO_GOT_OFFSET:
1248 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1249 case MONO_PATCH_INFO_AOT_MODULE:
1250 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1251 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1252 return hash;
1253 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1254 return hash | ji->data.uindex;
1255 case MONO_PATCH_INFO_JIT_ICALL_ID:
1256 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1257 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1258 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1259 return hash | ji->data.index;
1260 case MONO_PATCH_INFO_SWITCH:
1261 return hash | ji->data.table->table_size;
1262 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1263 return hash | (gssize)ji->data.gsharedvt_method->method;
1264 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1265 return hash | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1266 case MONO_PATCH_INFO_VIRT_METHOD: {
1267 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1269 return hash | (gssize)info->klass | (gssize)info->method;
1271 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1272 return hash | mono_signature_hash (ji->data.sig);
1273 default:
1274 printf ("info type: %d\n", ji->type);
1275 mono_print_ji (ji); printf ("\n");
1276 g_assert_not_reached ();
1277 case MONO_PATCH_INFO_NONE:
1278 return 0;
1283 * mono_patch_info_equal:
1285 * This might fail to recognize equivalent patches, i.e. floats, so its only
1286 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1287 * in AOT.
1289 gint
1290 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1292 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1293 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1295 MonoJumpInfoType const ji1_type = ji1->type;
1296 MonoJumpInfoType const ji2_type = ji2->type;
1298 if (ji1_type != ji2_type)
1299 return 0;
1301 switch (ji1_type) {
1302 case MONO_PATCH_INFO_RVA:
1303 case MONO_PATCH_INFO_LDSTR:
1304 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1305 case MONO_PATCH_INFO_LDTOKEN:
1306 case MONO_PATCH_INFO_DECLSEC:
1307 return ji1->data.token->image == ji2->data.token->image &&
1308 ji1->data.token->token == ji2->data.token->token &&
1309 ji1->data.token->has_context == ji2->data.token->has_context &&
1310 ji1->data.token->context.class_inst == ji2->data.token->context.class_inst &&
1311 ji1->data.token->context.method_inst == ji2->data.token->context.method_inst;
1312 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1313 case MONO_PATCH_INFO_LDSTR_LIT:
1314 return g_str_equal (ji1->data.name, ji2->data.name);
1315 case MONO_PATCH_INFO_RGCTX_FETCH:
1316 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1317 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1318 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1320 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);
1322 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1323 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1324 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1326 return c1->sig == c2->sig && c1->method == c2->method;
1328 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1329 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1330 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1331 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;
1332 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1333 return ji1->data.uindex == ji2->data.uindex;
1334 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1335 return ji1->data.index == ji2->data.index;
1336 case MONO_PATCH_INFO_JIT_ICALL_ID:
1337 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1338 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1339 return ji1->data.jit_icall_id == ji2->data.jit_icall_id;
1340 case MONO_PATCH_INFO_VIRT_METHOD:
1341 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1342 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1343 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig);
1344 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1345 case MONO_PATCH_INFO_NONE:
1346 return 1;
1347 default:
1348 break;
1351 return ji1->data.target == ji2->data.target;
1354 gpointer
1355 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1357 unsigned char *ip = patch_info->ip.i + code;
1358 gconstpointer target = NULL;
1360 error_init (error);
1362 switch (patch_info->type) {
1363 case MONO_PATCH_INFO_BB:
1365 * FIXME: This could be hit for methods without a prolog. Should use -1
1366 * but too much code depends on a 0 initial value.
1368 //g_assert (patch_info->data.bb->native_offset);
1369 target = patch_info->data.bb->native_offset + code;
1370 break;
1371 case MONO_PATCH_INFO_ABS:
1372 target = patch_info->data.target;
1373 break;
1374 case MONO_PATCH_INFO_LABEL:
1375 target = patch_info->data.inst->inst_c0 + code;
1376 break;
1377 case MONO_PATCH_INFO_IP:
1378 target = ip;
1379 break;
1380 case MONO_PATCH_INFO_JIT_ICALL_ID: {
1381 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1382 target = mono_icall_get_wrapper (mi);
1383 break;
1385 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1386 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1387 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1388 target = mi->func;
1389 break;
1391 case MONO_PATCH_INFO_METHOD_JUMP:
1392 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1393 if (!is_ok (error))
1394 return NULL;
1395 break;
1396 case MONO_PATCH_INFO_METHOD:
1397 if (patch_info->data.method == method) {
1398 target = code;
1399 } else {
1400 /* get the trampoline to the method from the domain */
1401 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1402 if (!is_ok (error))
1403 return NULL;
1405 break;
1406 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1408 * Return an ftndesc for either AOTed code, or for an interp entry.
1410 target = mini_llvmonly_load_method_ftndesc (patch_info->data.method, FALSE, FALSE, error);
1411 return_val_if_nok (error, NULL);
1412 break;
1414 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1415 gpointer code_slot;
1417 mono_domain_lock (domain);
1418 if (!domain_jit_info (domain)->method_code_hash)
1419 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1420 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1421 if (!code_slot) {
1422 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1423 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1425 mono_domain_unlock (domain);
1426 target = code_slot;
1427 break;
1429 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1430 target = (gpointer)&mono_polling_required;
1431 break;
1432 case MONO_PATCH_INFO_SWITCH: {
1433 gpointer *jump_table;
1434 int i;
1435 if (method && method->dynamic) {
1436 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1437 } else {
1438 if (mono_aot_only) {
1439 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1440 } else {
1441 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1445 for (i = 0; i < patch_info->data.table->table_size; i++) {
1446 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1449 target = jump_table;
1450 break;
1452 case MONO_PATCH_INFO_METHODCONST:
1453 case MONO_PATCH_INFO_CLASS:
1454 case MONO_PATCH_INFO_IMAGE:
1455 case MONO_PATCH_INFO_FIELD:
1456 case MONO_PATCH_INFO_SIGNATURE:
1457 case MONO_PATCH_INFO_AOT_MODULE:
1458 target = patch_info->data.target;
1459 break;
1460 case MONO_PATCH_INFO_IID:
1461 mono_class_init_internal (patch_info->data.klass);
1462 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1463 break;
1464 case MONO_PATCH_INFO_ADJUSTED_IID:
1465 mono_class_init_internal (patch_info->data.klass);
1466 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1467 break;
1468 case MONO_PATCH_INFO_VTABLE:
1469 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1470 mono_error_assert_ok (error);
1471 break;
1472 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1473 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1475 if (del_tramp->is_virtual)
1476 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1477 else
1478 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1479 break;
1481 case MONO_PATCH_INFO_SFLDA: {
1482 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1483 mono_error_assert_ok (error);
1485 if (mono_class_field_is_special_static (patch_info->data.field)) {
1486 gpointer addr = NULL;
1488 mono_domain_lock (domain);
1489 if (domain->special_static_fields)
1490 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1491 mono_domain_unlock (domain);
1492 g_assert (addr);
1493 return addr;
1496 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (!method || mono_class_needs_cctor_run (vtable->klass, method)))
1497 /* Done by the generated code */
1499 else {
1500 if (run_cctors) {
1501 if (!mono_runtime_class_init_full (vtable, error)) {
1502 return NULL;
1506 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1507 break;
1509 case MONO_PATCH_INFO_RVA: {
1510 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1511 guint32 rva;
1513 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1514 target = mono_image_rva_map (patch_info->data.token->image, rva);
1515 break;
1517 case MONO_PATCH_INFO_R4:
1518 case MONO_PATCH_INFO_R8:
1519 target = patch_info->data.target;
1520 break;
1521 case MONO_PATCH_INFO_EXC_NAME:
1522 target = patch_info->data.name;
1523 break;
1524 case MONO_PATCH_INFO_LDSTR:
1525 target =
1526 mono_ldstr_checked (domain, patch_info->data.token->image,
1527 mono_metadata_token_index (patch_info->data.token->token), error);
1528 break;
1529 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1530 gpointer handle;
1531 MonoClass *handle_class;
1533 handle = mono_ldtoken_checked (patch_info->data.token->image,
1534 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1535 if (!is_ok (error))
1536 return NULL;
1537 mono_class_init_internal (handle_class);
1538 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType *)handle));
1540 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1541 if (!is_ok (error))
1542 return NULL;
1543 break;
1545 case MONO_PATCH_INFO_LDTOKEN: {
1546 gpointer handle;
1547 MonoClass *handle_class;
1549 handle = mono_ldtoken_checked (patch_info->data.token->image,
1550 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1551 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1552 mono_class_init_internal (handle_class);
1554 target = handle;
1555 break;
1557 case MONO_PATCH_INFO_DECLSEC:
1558 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1559 break;
1560 case MONO_PATCH_INFO_ICALL_ADDR:
1561 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1562 /* run_cctors == 0 -> AOT */
1563 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1564 if (run_cctors) {
1565 target = mono_lookup_pinvoke_call_internal (patch_info->data.method, error);
1566 if (!target) {
1567 if (mono_aot_only)
1568 return NULL;
1569 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));
1571 } else {
1572 target = NULL;
1574 } else {
1575 target = mono_lookup_internal_call (patch_info->data.method);
1577 if (mono_is_missing_icall_addr (target) && run_cctors)
1578 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1580 break;
1581 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1582 target = &mono_thread_interruption_request_flag;
1583 break;
1584 case MONO_PATCH_INFO_METHOD_RGCTX:
1585 target = mini_method_get_rgctx (patch_info->data.method);
1586 break;
1587 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1588 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1590 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1591 break;
1593 case MONO_PATCH_INFO_BB_OVF:
1594 case MONO_PATCH_INFO_EXC_OVF:
1595 case MONO_PATCH_INFO_GOT_OFFSET:
1596 case MONO_PATCH_INFO_NONE:
1597 break;
1598 case MONO_PATCH_INFO_RGCTX_FETCH: {
1599 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1601 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1602 break;
1604 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1605 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1606 if (!run_cctors)
1607 /* AOT, not needed */
1608 target = NULL;
1609 else
1610 target = mono_arch_get_seq_point_info (domain, code);
1611 break;
1612 #endif
1613 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1614 int card_table_shift_bits;
1615 gpointer card_table_mask;
1617 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1618 break;
1620 case MONO_PATCH_INFO_GC_NURSERY_START: {
1621 int shift_bits;
1622 size_t size;
1624 target = mono_gc_get_nursery (&shift_bits, &size);
1625 break;
1627 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1628 int shift_bits;
1629 size_t size;
1631 mono_gc_get_nursery (&shift_bits, &size);
1633 target = (gpointer)(gssize)shift_bits;
1634 break;
1636 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1637 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1638 break;
1640 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1641 target = NULL;
1642 break;
1644 case MONO_PATCH_INFO_LDSTR_LIT: {
1645 int len;
1646 char *s;
1648 len = strlen ((const char *)patch_info->data.target);
1649 s = (char *)mono_domain_alloc0 (domain, len + 1);
1650 memcpy (s, patch_info->data.target, len);
1651 target = s;
1653 break;
1655 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1656 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1657 break;
1658 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1659 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1660 break;
1662 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1663 target = (gpointer) &mono_profiler_state.exception_clause_count;
1664 break;
1666 default:
1667 g_assert_not_reached ();
1670 return (gpointer)target;
1674 * mini_register_jump_site:
1676 * Register IP as a jump/tailcall site which calls METHOD.
1677 * This is needed because common_call_trampoline () cannot patch
1678 * the call site because the caller ip is not available for jumps.
1680 void
1681 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1683 MonoJumpList *jlist;
1685 MonoMethod *shared_method = mini_method_to_shared (method);
1686 method = shared_method ? shared_method : method;
1688 mono_domain_lock (domain);
1689 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1690 if (!jlist) {
1691 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1692 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1694 jlist->list = g_slist_prepend (jlist->list, ip);
1695 mono_domain_unlock (domain);
1699 * mini_patch_jump_sites:
1701 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1703 void
1704 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1706 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1708 if (!hash)
1709 return;
1711 MonoJumpInfo patch_info;
1712 MonoJumpList *jlist;
1713 GSList *tmp;
1715 /* The caller/callee might use different instantiations */
1716 MonoMethod *shared_method = mini_method_to_shared (method);
1717 method = shared_method ? shared_method : method;
1719 mono_domain_lock (domain);
1720 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1721 if (jlist)
1722 g_hash_table_remove (hash, method);
1723 mono_domain_unlock (domain);
1724 if (jlist) {
1725 patch_info.next = NULL;
1726 patch_info.ip.i = 0;
1727 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1728 patch_info.data.method = method;
1730 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1731 for (tmp = jlist->list; tmp; tmp = tmp->next)
1732 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1733 #else
1734 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1735 // for gshared methods
1736 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1737 ERROR_DECL (error);
1738 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1739 mono_error_assert_ok (error);
1741 #endif
1746 * mini_patch_llvm_jit_callees:
1748 * Patch function address slots used by llvm JITed code.
1750 void
1751 mini_patch_llvm_jit_callees (MonoDomain *domain, MonoMethod *method, gpointer addr)
1753 if (!domain_jit_info (domain)->llvm_jit_callees)
1754 return;
1755 GSList *callees = (GSList*)g_hash_table_lookup (domain_jit_info (domain)->llvm_jit_callees, method);
1756 GSList *l;
1758 for (l = callees; l; l = l->next) {
1759 gpointer *slot = (gpointer*)l->data;
1761 *slot = addr;
1765 void
1766 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1768 MonoGenericInst *inst;
1769 int i;
1771 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1773 if (context && context->class_inst) {
1774 inst = context->class_inst;
1775 for (i = 0; i < inst->type_argc; ++i) {
1776 MonoType *type = inst->type_argv [i];
1778 if (mini_is_gsharedvt_gparam (type))
1779 gsctx->is_gsharedvt = TRUE;
1782 if (context && context->method_inst) {
1783 inst = context->method_inst;
1785 for (i = 0; i < inst->type_argc; ++i) {
1786 MonoType *type = inst->type_argv [i];
1788 if (mini_is_gsharedvt_gparam (type))
1789 gsctx->is_gsharedvt = TRUE;
1795 * LOCKING: Acquires the jit code hash lock.
1797 MonoJitInfo*
1798 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1800 MonoJitInfo *ji;
1801 static gboolean inited = FALSE;
1802 static int lookups = 0;
1803 static int failed_lookups = 0;
1805 mono_domain_jit_code_hash_lock (domain);
1806 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1807 if (!ji && shared) {
1808 /* Try generic sharing */
1809 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1810 if (ji && !ji->has_generic_jit_info)
1811 ji = NULL;
1812 if (!inited) {
1813 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1814 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1815 inited = TRUE;
1818 ++lookups;
1819 if (!ji)
1820 ++failed_lookups;
1822 mono_domain_jit_code_hash_unlock (domain);
1824 return ji;
1827 static MonoJitInfo*
1828 lookup_method (MonoDomain *domain, MonoMethod *method)
1830 ERROR_DECL (error);
1831 MonoJitInfo *ji;
1832 MonoMethod *shared;
1834 ji = mini_lookup_method (domain, method, NULL);
1836 if (!ji) {
1837 if (!mono_method_is_generic_sharable (method, FALSE))
1838 return NULL;
1839 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1840 mono_error_assert_ok (error);
1841 ji = mini_lookup_method (domain, method, shared);
1844 return ji;
1847 MonoClass*
1848 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1850 ERROR_DECL (error);
1851 MonoClass *klass;
1853 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1854 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1855 if (context) {
1856 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1857 mono_error_cleanup (error); /* FIXME don't swallow the error */
1859 } else {
1860 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1861 mono_error_cleanup (error); /* FIXME don't swallow the error */
1863 if (klass)
1864 mono_class_init_internal (klass);
1865 return klass;
1868 #if ENABLE_JIT_MAP
1869 static FILE* perf_map_file;
1871 void
1872 mono_enable_jit_map (void)
1874 if (!perf_map_file) {
1875 char name [64];
1876 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1877 unlink (name);
1878 perf_map_file = fopen (name, "w");
1882 void
1883 mono_emit_jit_tramp (void *start, int size, const char *desc)
1885 if (perf_map_file)
1886 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1889 void
1890 mono_emit_jit_map (MonoJitInfo *jinfo)
1892 if (perf_map_file) {
1893 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1894 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1895 g_free (name);
1899 gboolean
1900 mono_jit_map_is_enabled (void)
1902 return perf_map_file != NULL;
1905 #endif
1907 static void
1908 no_gsharedvt_in_wrapper (void)
1910 g_assert_not_reached ();
1914 Overall algorithm:
1916 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.
1917 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1918 Dependency management in this case is too complex to justify implementing it.
1920 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1922 TODO:
1923 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1924 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1925 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1926 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1928 typedef struct {
1929 MonoMethod *method;
1930 MonoDomain *domain;
1931 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1932 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1933 int threads_waiting; /* Number of threads waiting on this job */
1934 gboolean has_cond; /* True if @cond was initialized */
1935 gboolean done; /* True if the method finished JIT'ing */
1936 MonoCoopCond cond; /* Cond sleeping threads wait one */
1937 } JitCompilationEntry;
1939 typedef struct {
1940 GPtrArray *in_flight_methods; //JitCompilationEntry*
1941 MonoCoopMutex lock;
1942 } JitCompilationData;
1945 Timeout, in millisecounds, that we wait other threads to finish JITing.
1946 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.
1948 #define MAX_JIT_TIMEOUT_MS 1000
1951 static JitCompilationData compilation_data;
1952 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
1954 static void
1955 mini_jit_init_job_control (void)
1957 mono_coop_mutex_init (&compilation_data.lock);
1958 compilation_data.in_flight_methods = g_ptr_array_new ();
1961 static void
1962 lock_compilation_data (void)
1964 mono_coop_mutex_lock (&compilation_data.lock);
1967 static void
1968 unlock_compilation_data (void)
1970 mono_coop_mutex_unlock (&compilation_data.lock);
1973 static JitCompilationEntry*
1974 find_method (MonoMethod *method, MonoDomain *domain)
1976 int i;
1977 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1978 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
1979 if (e->method == method && e->domain == domain)
1980 return e;
1983 return NULL;
1986 static void
1987 add_current_thread (MonoJitTlsData *jit_tls)
1989 ++jit_tls->active_jit_methods;
1992 static void
1993 unref_jit_entry (JitCompilationEntry *entry)
1995 --entry->ref_count;
1996 if (entry->ref_count)
1997 return;
1998 if (entry->has_cond)
1999 mono_coop_cond_destroy (&entry->cond);
2000 g_free (entry);
2004 * Returns true if this method waited successfully for another thread to JIT it
2006 static gboolean
2007 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2009 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2010 JitCompilationEntry *entry;
2012 static gboolean inited;
2013 if (!inited) {
2014 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2015 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2016 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2017 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2018 inited = TRUE;
2021 lock_compilation_data ();
2023 if (!(entry = find_method (method, domain))) {
2024 entry = g_new0 (JitCompilationEntry, 1);
2025 entry->method = method;
2026 entry->domain = domain;
2027 entry->compilation_count = entry->ref_count = 1;
2028 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2029 g_assert (find_method (method, domain) == entry);
2030 add_current_thread (jit_tls);
2032 unlock_compilation_data ();
2033 return FALSE;
2034 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2035 //We can't suspend the current thread if it's already JITing a method.
2036 //Dependency management is too compilated and we want to get rid of this anyways.
2038 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2039 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2041 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2042 ++entry->compilation_count;
2043 ++jit_methods_multiple;
2044 ++jit_tls->active_jit_methods;
2046 unlock_compilation_data ();
2047 return FALSE;
2048 } else {
2049 ++jit_methods_waited;
2050 ++entry->ref_count;
2052 if (!entry->has_cond) {
2053 mono_coop_cond_init (&entry->cond);
2054 entry->has_cond = TRUE;
2057 while (TRUE) {
2058 ++entry->threads_waiting;
2060 g_assert (entry->has_cond);
2061 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2062 --entry->threads_waiting;
2064 if (entry->done) {
2065 unref_jit_entry (entry);
2066 unlock_compilation_data ();
2067 return TRUE;
2068 } else {
2069 //We hit the timeout or a spurious wakeup, fallback to JITing
2070 g_assert (entry->ref_count > 1);
2071 unref_jit_entry (entry);
2072 ++jit_spurious_wakeups_or_timeouts;
2074 ++entry->compilation_count;
2075 ++jit_methods_multiple;
2076 ++jit_tls->active_jit_methods;
2078 unlock_compilation_data ();
2079 return FALSE;
2085 static void
2086 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2088 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2090 lock_compilation_data ();
2092 g_assert (jit_tls->active_jit_methods > 0);
2093 --jit_tls->active_jit_methods;
2095 JitCompilationEntry *entry = find_method (method, target_domain);
2096 g_assert (entry); // It would be weird to fail
2097 entry->done = TRUE;
2099 if (entry->threads_waiting) {
2100 g_assert (entry->has_cond);
2101 mono_coop_cond_broadcast (&entry->cond);
2104 if (--entry->compilation_count == 0) {
2105 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2106 unref_jit_entry (entry);
2109 unlock_compilation_data ();
2112 static MonoJitInfo*
2113 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2115 MonoDomain *domain = mono_get_root_domain ();
2116 MonoJitInfo *jinfo;
2117 guint8 *uw_info;
2118 guint32 info_len;
2120 if (info->uw_info) {
2121 uw_info = info->uw_info;
2122 info_len = info->uw_info_len;
2123 } else {
2124 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2127 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2128 jinfo->d.method = wrapper;
2129 jinfo->code_start = info->code;
2130 jinfo->code_size = info->code_size;
2131 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2133 if (!info->uw_info)
2134 g_free (uw_info);
2136 return jinfo;
2139 static gpointer
2140 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2142 MonoJitInfo *jinfo;
2143 gpointer code;
2145 if (mono_llvm_only) {
2146 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2147 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2149 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2151 * These wrappers are only created for signatures which are in the program, but
2152 * sometimes we load methods too eagerly and have to create them even if they
2153 * will never be called.
2155 return (gpointer)no_gsharedvt_in_wrapper;
2160 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2161 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2162 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2164 if (!piinfo->addr) {
2165 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2166 piinfo->addr = mono_lookup_internal_call (method);
2167 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2168 #ifdef HOST_WIN32
2169 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);
2170 #else
2171 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);
2172 #endif
2173 else {
2174 ERROR_DECL (ignored_error);
2175 mono_lookup_pinvoke_call_internal (method, ignored_error);
2176 mono_error_cleanup (ignored_error);
2180 MonoMethod *nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2181 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2182 return_val_if_nok (error, NULL);
2184 code = mono_get_addr_from_ftnptr (compiled_method);
2185 jinfo = mono_jit_info_table_find (target_domain, code);
2186 if (!jinfo)
2187 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2188 if (jinfo)
2189 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2190 return code;
2191 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2192 const char *name = method->name;
2193 char *full_name;
2194 MonoMethod *nm;
2196 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2197 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2198 MonoJitICallInfo *mi = &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor;
2200 * We need to make sure this wrapper
2201 * is compiled because it might end up
2202 * in an (M)RGCTX if generic sharing
2203 * is enabled, and would be called
2204 * indirectly. If it were a
2205 * trampoline we'd try to patch that
2206 * indirect call, which is not
2207 * possible.
2209 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2210 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2211 if (mono_llvm_only) {
2212 nm = mono_marshal_get_delegate_invoke (method, NULL);
2213 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2214 return_val_if_nok (error, NULL);
2215 return mono_get_addr_from_ftnptr (compiled_ptr);
2218 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2219 if (mono_use_interpreter)
2220 return NULL;
2222 return mono_create_delegate_trampoline (target_domain, method->klass);
2223 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2224 nm = mono_marshal_get_delegate_begin_invoke (method);
2225 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2226 return_val_if_nok (error, NULL);
2227 return mono_get_addr_from_ftnptr (compiled_ptr);
2228 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2229 nm = mono_marshal_get_delegate_end_invoke (method);
2230 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2231 return_val_if_nok (error, NULL);
2232 return mono_get_addr_from_ftnptr (compiled_ptr);
2236 full_name = mono_method_full_name (method, TRUE);
2237 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2238 g_free (full_name);
2239 return NULL;
2242 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2243 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2245 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2246 static MonoTrampInfo *in_tinfo, *out_tinfo;
2247 MonoTrampInfo *tinfo;
2248 MonoJitInfo *jinfo;
2249 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2251 if (is_in && in_tinfo)
2252 return in_tinfo->code;
2253 else if (!is_in && out_tinfo)
2254 return out_tinfo->code;
2257 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2258 * works.
2259 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2261 if (mono_ee_features.use_aot_trampolines)
2262 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2263 else
2264 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2265 jinfo = create_jit_info_for_trampoline (method, tinfo);
2266 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2267 if (is_in)
2268 in_tinfo = tinfo;
2269 else
2270 out_tinfo = tinfo;
2271 return tinfo->code;
2275 return NULL;
2278 static gpointer
2279 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2281 MonoDomain *target_domain, *domain = mono_domain_get ();
2282 MonoJitInfo *info;
2283 gpointer code = NULL, p;
2284 MonoJitInfo *ji;
2285 MonoJitICallInfo *callinfo = NULL;
2286 WrapperInfo *winfo = NULL;
2287 gboolean use_interp = FALSE;
2289 error_init (error);
2291 if (mono_ee_features.force_use_interpreter && !jit_only)
2292 use_interp = TRUE;
2293 if (!use_interp && mono_interp_only_classes) {
2294 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2295 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2296 use_interp = TRUE;
2299 if (use_interp) {
2300 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2301 if (code)
2302 return code;
2305 if (mono_llvm_only)
2306 /* Should be handled by the caller */
2307 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2310 * ICALL wrappers are handled specially, since there is only one copy of them
2311 * shared by all appdomains.
2313 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2314 winfo = mono_marshal_get_wrapper_info (method);
2315 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2316 callinfo = mono_find_jit_icall_info (winfo->d.icall.jit_icall_id);
2318 /* Must be domain neutral since there is only one copy */
2319 opt |= MONO_OPT_SHARED;
2320 } else {
2321 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2322 opt &= ~MONO_OPT_SHARED;
2325 if (opt & MONO_OPT_SHARED)
2326 target_domain = mono_get_root_domain ();
2327 else
2328 target_domain = domain;
2330 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2331 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2333 g_assert (info);
2334 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2335 MonoGenericContext *ctx = NULL;
2336 if (method->is_inflated)
2337 ctx = mono_method_get_context (method);
2338 method = info->d.synchronized_inner.method;
2339 if (ctx) {
2340 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2341 g_assert (is_ok (error)); /* FIXME don't swallow the error */
2346 lookup_start:
2347 info = lookup_method (target_domain, method);
2348 if (info) {
2349 /* We can't use a domain specific method in another domain */
2350 if (! ((domain != target_domain) && !info->domain_neutral)) {
2351 MonoVTable *vtable;
2353 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2354 vtable = mono_class_vtable_checked (domain, method->klass, error);
2355 if (!is_ok (error))
2356 return NULL;
2357 g_assert (vtable);
2358 if (!mono_runtime_class_init_full (vtable, error))
2359 return NULL;
2360 return mono_create_ftnptr (target_domain, info->code_start);
2364 #ifdef MONO_USE_AOT_COMPILER
2365 if (opt & MONO_OPT_AOT) {
2366 MonoDomain *domain = NULL;
2368 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2369 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2370 g_assert (info);
2371 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2372 /* AOT'd wrappers for interp must be owned by root domain */
2373 domain = mono_get_root_domain ();
2376 if (!domain)
2377 domain = mono_domain_get ();
2379 mono_class_init_internal (method->klass);
2381 code = mono_aot_get_method (domain, method, error);
2382 if (code) {
2383 MonoVTable *vtable;
2385 if (mono_gc_is_critical_method (method)) {
2387 * The suspend code needs to be able to lookup these methods by ip in async context,
2388 * so preload their jit info.
2390 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2391 g_assert (ji);
2395 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2396 * This is not a problem, since it will be initialized when the method is first
2397 * called by init_method ().
2399 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2400 vtable = mono_class_vtable_checked (domain, method->klass, error);
2401 mono_error_assert_ok (error);
2402 if (!mono_runtime_class_init_full (vtable, error))
2403 return NULL;
2406 if (!is_ok (error))
2407 return NULL;
2409 #endif
2411 if (!code) {
2412 code = compile_special (method, target_domain, error);
2414 if (!is_ok (error))
2415 return NULL;
2418 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER) {
2419 if (mono_llvm_only) {
2420 /* Signal to the caller that AOTed code is not found */
2421 return NULL;
2423 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2425 if (!is_ok (error))
2426 return NULL;
2429 if (!code) {
2430 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2431 char *full_name = mono_type_get_full_name (method->klass);
2432 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2433 g_free (full_name);
2434 return NULL;
2437 if (mono_aot_only) {
2438 char *fullname = mono_method_get_full_name (method);
2439 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);
2440 g_free (fullname);
2442 return NULL;
2445 if (wait_or_register_method_to_compile (method, target_domain))
2446 goto lookup_start;
2447 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2448 unregister_method_for_compile (method, target_domain);
2450 if (!is_ok (error))
2451 return NULL;
2453 if (!code && mono_llvm_only) {
2454 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2455 g_assert_not_reached ();
2458 if (!code)
2459 return NULL;
2461 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2462 #ifndef HOST_WASM
2463 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2464 MonoDomain *d;
2467 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2469 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2470 g_assert (ji);
2472 #endif
2474 p = mono_create_ftnptr (target_domain, code);
2476 if (callinfo) {
2477 // FIXME Locking here is somewhat historical due to mono_register_jit_icall_wrapper taking loader lock.
2478 // atomic_compare_exchange should suffice.
2479 mono_loader_lock ();
2480 mono_jit_lock ();
2481 if (!callinfo->wrapper) {
2482 callinfo->wrapper = p;
2484 mono_jit_unlock ();
2485 mono_loader_unlock ();
2488 // FIXME p or callinfo->wrapper or does not matter?
2489 return p;
2492 gpointer
2493 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2495 gpointer code;
2497 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2498 return code;
2502 * mono_jit_compile_method_jit_only:
2504 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2506 gpointer
2507 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2509 gpointer code;
2511 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2512 return code;
2515 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2516 static void
2517 invalidated_delegate_trampoline (char *desc)
2519 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2520 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2521 desc);
2523 #endif
2526 * mono_jit_free_method:
2528 * Free all memory allocated by the JIT for METHOD.
2530 static void
2531 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2533 MonoJitDynamicMethodInfo *ji;
2534 gboolean destroy = TRUE, removed;
2535 GHashTableIter iter;
2536 MonoJumpList *jlist;
2537 MonoJitDomainInfo *info = domain_jit_info (domain);
2539 g_assert (method->dynamic);
2541 if (mono_use_interpreter) {
2542 mono_domain_jit_code_hash_lock (domain);
2543 /* InterpMethod is allocated in the domain mempool. We might haven't
2544 * allocated an InterpMethod for this instance yet */
2545 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2546 mono_domain_jit_code_hash_unlock (domain);
2549 mono_domain_lock (domain);
2550 ji = mono_dynamic_code_hash_lookup (domain, method);
2551 mono_domain_unlock (domain);
2553 if (!ji)
2554 return;
2556 mono_debug_remove_method (method, domain);
2557 mono_lldb_remove_method (domain, method, ji);
2559 mono_domain_lock (domain);
2560 g_hash_table_remove (info->dynamic_code_hash, method);
2561 mono_domain_jit_code_hash_lock (domain);
2562 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2563 g_assert (removed);
2564 mono_domain_jit_code_hash_unlock (domain);
2565 g_hash_table_remove (info->jump_trampoline_hash, method);
2566 g_hash_table_remove (info->seq_points, method);
2568 ji->ji->seq_points = NULL;
2570 /* requires the domain lock - took above */
2571 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2573 /* Remove jump targets in this method */
2574 g_hash_table_iter_init (&iter, info->jump_target_hash);
2575 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2576 GSList *tmp, *remove;
2578 remove = NULL;
2579 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2580 guint8 *ip = (guint8 *)tmp->data;
2582 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2583 remove = g_slist_prepend (remove, tmp);
2585 for (tmp = remove; tmp; tmp = tmp->next) {
2586 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2588 g_slist_free (remove);
2590 mono_domain_unlock (domain);
2592 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2593 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2595 * Instead of freeing the code, change it to call an error routine
2596 * so people can fix their code.
2598 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2599 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2601 g_free (type);
2602 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2603 destroy = FALSE;
2605 #endif
2608 * This needs to be done before freeing code_mp, since the code address is the
2609 * key in the table, so if we free the code_mp first, another thread can grab the
2610 * same code address and replace our entry in the table.
2612 mono_jit_info_table_remove (domain, ji->ji);
2614 if (destroy)
2615 mono_code_manager_destroy (ji->code_mp);
2616 g_free (ji);
2619 gpointer
2620 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2622 gpointer code;
2623 MonoJitInfo *ji;
2625 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2626 if (!code) {
2627 ERROR_DECL (oerror);
2629 /* Might be AOTed code */
2630 mono_class_init_internal (method->klass);
2631 code = mono_aot_get_method (domain, method, oerror);
2632 if (code) {
2633 mono_error_assert_ok (oerror);
2634 ji = mono_jit_info_table_find (domain, code);
2635 } else {
2636 if (!is_ok (oerror))
2637 mono_error_cleanup (oerror);
2639 /* Might be interpreted */
2640 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2644 *out_ji = ji;
2646 return code;
2649 gpointer
2650 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2652 MonoDomain *target_domain;
2653 MonoJitInfo *info;
2655 if (default_opt & MONO_OPT_SHARED)
2656 target_domain = mono_get_root_domain ();
2657 else
2658 target_domain = domain;
2660 info = lookup_method (target_domain, method);
2661 if (info) {
2662 /* We can't use a domain specific method in another domain */
2663 if (! ((domain != target_domain) && !info->domain_neutral)) {
2664 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2665 if (ji)
2666 *ji = info;
2667 return info->code_start;
2671 if (ji)
2672 *ji = NULL;
2673 return NULL;
2676 static guint32 bisect_opt = 0;
2677 static GHashTable *bisect_methods_hash = NULL;
2679 void
2680 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2682 FILE *file;
2683 char method_name [2048];
2685 bisect_opt = opt;
2686 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2687 g_assert (bisect_methods_hash);
2689 file = fopen (method_list_filename, "r");
2690 g_assert (file);
2692 while (fgets (method_name, sizeof (method_name), file)) {
2693 size_t len = strlen (method_name);
2694 g_assert (len > 0);
2695 g_assert (method_name [len - 1] == '\n');
2696 method_name [len - 1] = 0;
2697 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2699 g_assert (feof (file));
2702 gboolean mono_do_single_method_regression = FALSE;
2703 guint32 mono_single_method_regression_opt = 0;
2704 MonoMethod *mono_current_single_method;
2705 GSList *mono_single_method_list;
2706 GHashTable *mono_single_method_hash;
2708 guint32
2709 mono_get_optimizations_for_method (MonoMethod *method, guint32 opt)
2711 g_assert (method);
2713 if (bisect_methods_hash) {
2714 char *name = mono_method_full_name (method, TRUE);
2715 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2716 g_free (name);
2717 if (res)
2718 return opt | bisect_opt;
2720 if (!mono_do_single_method_regression)
2721 return opt;
2722 if (!mono_current_single_method) {
2723 if (!mono_single_method_hash)
2724 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2725 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2726 g_hash_table_insert (mono_single_method_hash, method, method);
2727 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2729 return opt;
2731 if (method == mono_current_single_method)
2732 return mono_single_method_regression_opt;
2733 return opt;
2736 gpointer
2737 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2739 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2742 typedef struct {
2743 MonoMethod *method;
2744 gpointer compiled_method;
2745 gpointer runtime_invoke;
2746 MonoVTable *vtable;
2747 MonoDynCallInfo *dyn_call_info;
2748 MonoClass *ret_box_class;
2749 MonoMethodSignature *sig;
2750 gboolean gsharedvt_invoke;
2751 gboolean use_interp;
2752 gpointer *wrapper_arg;
2753 } RuntimeInvokeInfo;
2755 static RuntimeInvokeInfo*
2756 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2758 MonoMethod *invoke;
2759 RuntimeInvokeInfo *info = NULL;
2760 RuntimeInvokeInfo *ret = NULL;
2762 info = g_new0 (RuntimeInvokeInfo, 1);
2763 info->compiled_method = compiled_method;
2764 info->use_interp = use_interp;
2765 if (mono_llvm_only && method->string_ctor)
2766 info->sig = mono_marshal_get_string_ctor_signature (method);
2767 else
2768 info->sig = mono_method_signature_internal (method);
2770 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2771 (void)invoke;
2772 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2773 if (!is_ok (error))
2774 goto exit;
2775 g_assert (info->vtable);
2777 MonoMethodSignature *sig;
2778 sig = info->sig;
2779 MonoType *ret_type;
2782 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2783 * in full-aot mode, so we use a slower, but more generic wrapper if
2784 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2786 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2787 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2788 gboolean supported = TRUE;
2789 int i;
2791 if (method->string_ctor)
2792 sig = mono_marshal_get_string_ctor_signature (method);
2794 for (i = 0; i < sig->param_count; ++i) {
2795 MonoType *t = sig->params [i];
2797 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
2798 supported = FALSE;
2801 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2802 supported = FALSE;
2804 if (supported) {
2805 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2806 if (mini_debug_options.dyn_runtime_invoke)
2807 g_assert (info->dyn_call_info);
2810 #endif
2812 ret_type = sig->ret;
2813 switch (ret_type->type) {
2814 case MONO_TYPE_VOID:
2815 break;
2816 case MONO_TYPE_I1:
2817 case MONO_TYPE_U1:
2818 case MONO_TYPE_I2:
2819 case MONO_TYPE_U2:
2820 case MONO_TYPE_I4:
2821 case MONO_TYPE_U4:
2822 case MONO_TYPE_I:
2823 case MONO_TYPE_U:
2824 case MONO_TYPE_I8:
2825 case MONO_TYPE_U8:
2826 case MONO_TYPE_BOOLEAN:
2827 case MONO_TYPE_CHAR:
2828 case MONO_TYPE_R4:
2829 case MONO_TYPE_R8:
2830 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2831 break;
2832 case MONO_TYPE_PTR:
2833 info->ret_box_class = mono_defaults.int_class;
2834 break;
2835 case MONO_TYPE_STRING:
2836 case MONO_TYPE_CLASS:
2837 case MONO_TYPE_ARRAY:
2838 case MONO_TYPE_SZARRAY:
2839 case MONO_TYPE_OBJECT:
2840 break;
2841 case MONO_TYPE_GENERICINST:
2842 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2843 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2844 break;
2845 case MONO_TYPE_VALUETYPE:
2846 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2847 break;
2848 default:
2849 g_assert_not_reached ();
2850 break;
2853 if (info->use_interp) {
2854 ret = info;
2855 info = NULL;
2856 goto exit;
2859 if (!info->dyn_call_info) {
2860 if (mono_llvm_only) {
2861 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2862 g_assert_not_reached ();
2863 #endif
2864 info->gsharedvt_invoke = TRUE;
2865 if (!callee_gsharedvt) {
2866 /* Invoke a gsharedvt out wrapper instead */
2867 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2868 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2870 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2871 info->wrapper_arg [0] = mini_llvmonly_add_method_wrappers (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2873 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2874 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2875 g_free (wrapper_sig);
2877 info->compiled_method = mono_jit_compile_method (wrapper, error);
2878 if (!is_ok (error))
2879 goto exit;
2880 } else {
2881 /* Gsharedvt methods can be invoked the same way */
2882 /* The out wrapper has the same signature as the compiled gsharedvt method */
2883 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2885 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
2887 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2888 g_free (wrapper_sig);
2891 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2892 if (!is_ok (error))
2893 goto exit;
2896 ret = info;
2897 info = NULL;
2898 exit:
2899 g_free (info);
2900 return ret;
2903 static MonoObject*
2904 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2906 MonoMethodSignature *sig = info->sig;
2907 MonoDomain *domain = mono_domain_get ();
2908 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2909 gpointer retval_ptr;
2910 guint8 retval [256];
2911 int i, pindex;
2913 error_init (error);
2915 g_assert (info->gsharedvt_invoke);
2918 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2919 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2920 * signatures, so we only have to generate runtime invoke wrappers for these
2921 * signatures.
2922 * This code also handles invocation of gsharedvt methods directly, no
2923 * out wrappers are used in that case.
2925 // allocate param_refs = param_count and args = param_count + hasthis + 2.
2926 int const param_count = sig->param_count;
2927 gpointer* const param_refs = g_newa (gpointer, param_count * 2 + sig->hasthis + 2);
2928 gpointer* const args = param_refs + param_count;
2929 pindex = 0;
2931 * The runtime invoke wrappers expects pointers to primitive types, so have to
2932 * use indirections.
2934 if (sig->hasthis)
2935 args [pindex ++] = &obj;
2936 if (sig->ret->type != MONO_TYPE_VOID) {
2937 retval_ptr = &retval;
2938 args [pindex ++] = &retval_ptr;
2940 for (i = 0; i < sig->param_count; ++i) {
2941 MonoType *t = sig->params [i];
2943 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
2944 MonoClass *klass = mono_class_from_mono_type_internal (t);
2945 guint8 *nullable_buf;
2946 int size;
2948 size = mono_class_value_size (klass, NULL);
2949 nullable_buf = g_alloca (size);
2950 g_assert (nullable_buf);
2952 /* The argument pointed to by params [i] is either a boxed vtype or null */
2953 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2954 params [i] = nullable_buf;
2957 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2958 param_refs [i] = params [i];
2959 params [i] = &(param_refs [i]);
2961 args [pindex ++] = &params [i];
2963 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2964 args [pindex ++] = &info->wrapper_arg;
2966 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2968 runtime_invoke (NULL, args, exc, info->compiled_method);
2969 if (exc && *exc)
2970 return NULL;
2972 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2973 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2974 else
2975 return *(MonoObject**)retval;
2979 * mono_jit_runtime_invoke:
2980 * \param method: the method to invoke
2981 * \param obj: this pointer
2982 * \param params: array of parameter values.
2983 * \param exc: Set to the exception raised in the managed method.
2984 * \param error: error or caught exception object
2985 * If \p exc is NULL, \p error is thrown instead.
2986 * If coop is enabled, \p exc argument is ignored -
2987 * all exceptions are caught and propagated through \p error
2989 static MonoObject*
2990 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2992 MonoMethod *invoke, *callee;
2993 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2994 MonoDomain *domain = mono_domain_get ();
2995 MonoJitDomainInfo *domain_info;
2996 RuntimeInvokeInfo *info, *info2;
2997 MonoJitInfo *ji = NULL;
2998 gboolean callee_gsharedvt = FALSE;
3000 if (mono_ee_features.force_use_interpreter)
3001 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3003 error_init (error);
3004 if (exc)
3005 *exc = NULL;
3007 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
3008 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3009 return NULL;
3012 domain_info = domain_jit_info (domain);
3014 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3016 if (!info) {
3017 if (mono_security_core_clr_enabled ()) {
3019 * This might be redundant since mono_class_vtable () already does this,
3020 * but keep it just in case for moonlight.
3022 mono_class_setup_vtable (method->klass);
3023 if (mono_class_has_failure (method->klass)) {
3024 mono_error_set_for_class_failure (error, method->klass);
3025 if (exc)
3026 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3027 return NULL;
3031 gpointer compiled_method;
3033 callee = method;
3034 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3035 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3037 * Array Get/Set/Address methods. The JIT implements them using inline code
3038 * inside the runtime invoke wrappers, so no need to compile them.
3040 if (mono_aot_only) {
3042 * Call a wrapper, since the runtime invoke wrapper was not generated.
3044 MonoMethod *wrapper;
3046 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3047 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3048 callee = wrapper;
3049 } else {
3050 callee = NULL;
3054 gboolean use_interp = FALSE;
3056 if (callee) {
3057 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3058 if (!compiled_method) {
3059 g_assert (!is_ok (error));
3061 if (mono_use_interpreter)
3062 use_interp = TRUE;
3063 else
3064 return NULL;
3065 } else {
3066 if (mono_llvm_only) {
3067 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3068 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3069 if (callee_gsharedvt)
3070 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3073 if (!callee_gsharedvt)
3074 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3076 } else {
3077 compiled_method = NULL;
3080 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3081 if (!is_ok (error))
3082 return NULL;
3084 mono_domain_lock (domain);
3085 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3086 mono_domain_unlock (domain);
3087 if (info2) {
3088 g_free (info);
3089 info = info2;
3094 * We need this here because mono_marshal_get_runtime_invoke can place
3095 * the helper method in System.Object and not the target class.
3097 if (!mono_runtime_class_init_full (info->vtable, error)) {
3098 if (exc)
3099 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3100 return NULL;
3103 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3104 we always catch the exception and propagate it through the MonoError */
3105 gboolean catchExcInMonoError =
3106 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3107 MonoObject *invoke_exc = NULL;
3108 if (catchExcInMonoError)
3109 exc = &invoke_exc;
3111 /* The wrappers expect this to be initialized to NULL */
3112 if (exc)
3113 *exc = NULL;
3115 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3116 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3117 if (info->dyn_call_info) {
3118 if (!dyn_runtime_invoke) {
3119 mono_domain_lock (domain);
3121 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3122 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3123 if (!dyn_runtime_invoke && mono_use_interpreter) {
3124 info->use_interp = TRUE;
3125 info->dyn_call_info = NULL;
3126 } else if (!is_ok (error)) {
3127 mono_domain_unlock (domain);
3128 return NULL;
3130 mono_domain_unlock (domain);
3133 if (info->dyn_call_info) {
3134 MonoMethodSignature *sig = mono_method_signature_internal (method);
3135 gpointer *args;
3136 int i, pindex, buf_size;
3137 guint8 *buf;
3138 guint8 retval [256];
3140 /* Convert the arguments to the format expected by start_dyn_call () */
3141 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3142 pindex = 0;
3143 if (sig->hasthis)
3144 args [pindex ++] = &obj;
3145 for (i = 0; i < sig->param_count; ++i) {
3146 MonoType *t = sig->params [i];
3148 if (t->byref) {
3149 args [pindex ++] = &params [i];
3150 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3151 args [pindex ++] = &params [i];
3152 } else {
3153 args [pindex ++] = params [i];
3157 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3159 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3160 buf = g_alloca (buf_size);
3161 memset (buf, 0, buf_size);
3162 g_assert (buf);
3164 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3166 dyn_runtime_invoke (buf, exc, info->compiled_method);
3167 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3169 if (catchExcInMonoError && *exc != NULL) {
3170 mono_error_set_exception_instance (error, (MonoException*) *exc);
3171 return NULL;
3174 if (info->ret_box_class)
3175 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3176 else
3177 return *(MonoObject**)retval;
3179 #endif
3181 MonoObject *result;
3183 if (info->use_interp) {
3184 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3185 return_val_if_nok (error, NULL);
3186 } else if (mono_llvm_only) {
3187 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3188 if (!is_ok (error))
3189 return NULL;
3190 } else {
3191 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3193 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3195 if (catchExcInMonoError && *exc != NULL) {
3196 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3197 mono_error_set_exception_instance (error, (MonoException*) *exc);
3199 return result;
3202 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3204 MonoException *exc = NULL;
3205 MonoJitInfo *ji;
3206 MonoContext mctx;
3207 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3208 MONO_SIG_HANDLER_GET_CONTEXT;
3210 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3212 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3214 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3215 if (mono_arch_is_int_overflow (ctx, info))
3217 * The spec says this throws ArithmeticException, but MS throws the derived
3218 * OverflowException.
3220 exc = mono_get_exception_overflow ();
3221 else
3222 exc = mono_get_exception_divide_by_zero ();
3223 #else
3224 exc = mono_get_exception_divide_by_zero ();
3225 #endif
3227 if (!ji) {
3228 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3229 goto exit;
3231 mono_sigctx_to_monoctx (ctx, &mctx);
3232 if (mono_dump_start ())
3233 mono_handle_native_crash ("SIGFPE", &mctx, info);
3234 if (mono_do_crash_chaining) {
3235 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3236 goto exit;
3240 mono_arch_handle_exception (ctx, exc);
3242 exit:
3243 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3246 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3248 MonoContext mctx;
3249 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3250 MONO_SIG_HANDLER_GET_CONTEXT;
3252 if (mono_runtime_get_no_exec ())
3253 exit (1);
3255 mono_sigctx_to_monoctx (ctx, &mctx);
3256 if (mono_dump_start ())
3257 mono_handle_native_crash ("SIGILL", &mctx, info);
3258 if (mono_do_crash_chaining) {
3259 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3260 return;
3265 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3267 #define HAVE_SIG_INFO
3268 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3270 #ifdef MONO_SIG_HANDLER_DEBUG
3271 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3272 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3273 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3274 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3275 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3276 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3277 #endif
3279 #endif
3281 gboolean
3282 mono_is_addr_implicit_null_check (void *addr)
3284 /* implicit null checks are only expected to work on the first page. larger
3285 * offsets are expected to have an explicit null check */
3286 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3289 // This function is separate from mono_sigsegv_signal_handler
3290 // so debug_fault_addr can be seen in debugger stacks.
3291 #ifdef MONO_SIG_HANDLER_DEBUG
3292 MONO_NEVER_INLINE
3293 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3294 #else
3295 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3296 #endif
3298 MonoJitInfo *ji = NULL;
3299 MonoDomain *domain = mono_domain_get ();
3300 gpointer fault_addr = NULL;
3301 MonoContext mctx;
3303 #if defined(HAVE_SIG_INFO) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3304 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3305 #endif
3306 #ifdef HAVE_SIG_INFO
3307 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3308 #else
3309 void *info = NULL;
3310 #endif
3311 MONO_SIG_HANDLER_GET_CONTEXT;
3313 mono_sigctx_to_monoctx (ctx, &mctx);
3315 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3316 if (mono_arch_is_single_step_event (info, ctx)) {
3317 mini_get_dbg_callbacks ()->single_step_event (ctx);
3318 return;
3319 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3320 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3321 return;
3323 #endif
3325 #if defined(HAVE_SIG_INFO)
3326 #if !defined(HOST_WIN32)
3327 fault_addr = info->si_addr;
3328 if (mono_aot_is_pagefault (info->si_addr)) {
3329 mono_aot_handle_pagefault (info->si_addr);
3330 return;
3332 #endif
3334 /* The thread might no be registered with the runtime */
3335 if (!mono_domain_get () || !jit_tls) {
3336 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3337 return;
3338 if (mono_dump_start())
3339 mono_handle_native_crash ("SIGSEGV", &mctx, info);
3340 if (mono_do_crash_chaining) {
3341 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3342 return;
3345 #endif
3347 if (domain)
3348 ji = mono_jit_info_table_find_internal (domain, mono_arch_ip_from_context (ctx), TRUE, TRUE);
3350 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3351 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3352 return;
3354 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3355 fault_addr = info->si_addr;
3356 if (fault_addr == NULL) {
3357 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3360 if (jit_tls && jit_tls->stack_size &&
3361 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3363 * The hard-guard page has been hit: there is not much we can do anymore
3364 * Print a hopefully clear message and abort.
3366 mono_handle_hard_stack_ovf (jit_tls, ji, &mctx, (guint8*)info->si_addr);
3367 g_assert_not_reached ();
3368 } else {
3369 /* The original handler might not like that it is executed on an altstack... */
3370 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3371 return;
3373 #ifdef TARGET_AMD64
3374 /* exceptions-amd64.c handles the check itself */
3375 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3376 #else
3377 if (mono_is_addr_implicit_null_check (info->si_addr)) {
3378 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3379 } else {
3380 // FIXME: This shouldn't run on the altstack
3381 if (mono_dump_start ())
3382 mono_handle_native_crash ("SIGSEGV", &mctx, info);
3384 #endif
3386 #else
3388 if (!ji) {
3389 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3390 return;
3392 if (mono_dump_start ())
3393 mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3395 if (mono_do_crash_chaining) {
3396 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3397 return;
3401 if (mono_is_addr_implicit_null_check (fault_addr)) {
3402 mono_arch_handle_exception (ctx, NULL);
3403 } else {
3404 if (mono_dump_start ())
3405 mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3407 #endif
3410 #ifdef MONO_SIG_HANDLER_DEBUG
3412 // This function is separate from mono_sigsegv_signal_handler_debug
3413 // so debug_fault_addr can be seen in debugger stacks.
3414 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3416 #ifdef HOST_WIN32
3417 gpointer const debug_fault_addr = (gpointer)MONO_SIG_HANDLER_GET_INFO () ->ep->ExceptionRecord->ExceptionInformation [1];
3418 #elif defined (HAVE_SIG_INFO)
3419 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3420 #else
3421 #error No extra parameter is passed, not even 0, to avoid any confusion.
3422 #endif
3423 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3426 #endif // MONO_SIG_HANDLER_DEBUG
3428 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3430 MonoException *exc;
3431 MONO_SIG_HANDLER_GET_CONTEXT;
3433 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3435 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3437 mono_arch_handle_exception (ctx, exc);
3439 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3442 #ifndef DISABLE_REMOTING
3443 /* mono_jit_create_remoting_trampoline:
3444 * @method: pointer to the method info
3446 * Creates a trampoline which calls the remoting functions. This
3447 * is used in the vtable of transparent proxies.
3449 * Returns: a pointer to the newly created code
3451 static gpointer
3452 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3454 MonoMethod *nm;
3455 guint8 *addr = NULL;
3457 error_init (error);
3459 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3460 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3461 domain, NULL);
3464 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3465 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3466 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3467 else
3468 nm = method;
3469 return_val_if_nok (error, NULL);
3470 addr = (guint8 *)mono_compile_method_checked (nm, error);
3471 return_val_if_nok (error, NULL);
3472 return mono_get_addr_from_ftnptr (addr);
3474 #endif
3476 static G_GNUC_UNUSED void
3477 no_imt_trampoline (void)
3479 g_assert_not_reached ();
3482 static G_GNUC_UNUSED void
3483 no_vcall_trampoline (void)
3485 g_assert_not_reached ();
3488 static gpointer *vtable_trampolines;
3489 static int vtable_trampolines_size;
3491 gpointer
3492 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3494 int index = slot_index + MONO_IMT_SIZE;
3496 if (mono_llvm_only)
3497 return mini_llvmonly_get_vtable_trampoline (vt, slot_index, index);
3499 g_assert (slot_index >= - MONO_IMT_SIZE);
3500 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3501 mono_jit_lock ();
3502 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3503 int new_size;
3504 gpointer new_table;
3506 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3507 while (new_size <= index)
3508 new_size *= 2;
3509 new_table = g_new0 (gpointer, new_size);
3511 if (vtable_trampolines)
3512 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3513 g_free (vtable_trampolines);
3514 mono_memory_barrier ();
3515 vtable_trampolines = (void **)new_table;
3516 vtable_trampolines_size = new_size;
3518 mono_jit_unlock ();
3521 if (!vtable_trampolines [index])
3522 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3523 return vtable_trampolines [index];
3526 static gpointer
3527 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3529 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3532 static gboolean
3533 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3535 if (mono_llvm_only)
3536 return FALSE;
3538 gpointer *imt = (gpointer*)vt;
3539 imt -= MONO_IMT_SIZE;
3541 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3544 static gpointer
3545 create_delegate_method_ptr (MonoMethod *method, MonoError *error)
3547 gpointer func;
3549 if (method_is_dynamic (method)) {
3550 /* Creating a trampoline would leak memory */
3551 func = mono_compile_method_checked (method, error);
3552 return_val_if_nok (error, NULL);
3553 } else {
3554 gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
3555 return_val_if_nok (error, NULL);
3556 func = mono_create_ftnptr (mono_domain_get (), trampoline);
3558 return func;
3561 static void
3562 mini_init_delegate (MonoDelegateHandle delegate, MonoError *error)
3564 MonoDelegate *del = MONO_HANDLE_RAW (delegate);
3566 if (mono_use_interpreter) {
3567 mini_get_interp_callbacks ()->init_delegate (del, error);
3568 return_if_nok (error);
3571 if (mono_llvm_only) {
3572 g_assert (del->method);
3573 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3574 del->method_ptr = mini_llvmonly_load_method_delegate (del->method, FALSE, FALSE, &del->extra_arg, error);
3575 } else if (!del->method_ptr && !del->interp_method) {
3576 del->method_ptr = create_delegate_method_ptr (del->method, error);
3577 return_if_nok (error);
3581 char*
3582 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3584 int abs_offset;
3586 abs_offset = offset;
3587 if (abs_offset < 0)
3588 abs_offset = - abs_offset;
3589 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3592 gpointer
3593 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3595 gboolean is_virtual_generic, is_interface, load_imt_reg;
3596 int offset, idx;
3598 static guint8 **cache = NULL;
3599 static int cache_size = 0;
3601 if (!method)
3602 return NULL;
3604 if (MONO_TYPE_ISSTRUCT (sig->ret))
3605 return NULL;
3607 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3608 is_interface = mono_class_is_interface (method->klass);
3609 load_imt_reg = is_virtual_generic || is_interface;
3611 if (is_interface)
3612 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3613 else
3614 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3616 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3617 g_assert (idx >= 0);
3619 /* Resize the cache to idx + 1 */
3620 if (cache_size < idx + 1) {
3621 mono_jit_lock ();
3622 if (cache_size < idx + 1) {
3623 guint8 **new_cache;
3624 int new_cache_size = idx + 1;
3626 new_cache = g_new0 (guint8*, new_cache_size);
3627 if (cache)
3628 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3629 g_free (cache);
3631 mono_memory_barrier ();
3632 cache = new_cache;
3633 cache_size = new_cache_size;
3635 mono_jit_unlock ();
3638 if (cache [idx])
3639 return cache [idx];
3641 /* FIXME Support more cases */
3642 if (mono_ee_features.use_aot_trampolines) {
3643 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3644 g_assert (cache [idx]);
3645 } else {
3646 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3648 return cache [idx];
3652 * mini_parse_debug_option:
3653 * @option: The option to parse.
3655 * Parses debug options for the mono runtime. The options are the same as for
3656 * the MONO_DEBUG environment variable.
3659 gboolean
3660 mini_parse_debug_option (const char *option)
3662 // Empty string is ok as consequence of appending ",foo"
3663 // without first checking for empty.
3664 if (*option == 0)
3665 return TRUE;
3667 if (!strcmp (option, "handle-sigint"))
3668 mini_debug_options.handle_sigint = TRUE;
3669 else if (!strcmp (option, "keep-delegates"))
3670 mini_debug_options.keep_delegates = TRUE;
3671 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3672 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3673 else if (!strcmp (option, "collect-pagefault-stats"))
3674 mini_debug_options.collect_pagefault_stats = TRUE;
3675 else if (!strcmp (option, "break-on-unverified"))
3676 mini_debug_options.break_on_unverified = TRUE;
3677 else if (!strcmp (option, "no-gdb-backtrace"))
3678 mini_debug_options.no_gdb_backtrace = TRUE;
3679 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3680 mini_debug_options.suspend_on_native_crash = TRUE;
3681 else if (!strcmp (option, "suspend-on-exception"))
3682 mini_debug_options.suspend_on_exception = TRUE;
3683 else if (!strcmp (option, "suspend-on-unhandled"))
3684 mini_debug_options.suspend_on_unhandled = TRUE;
3685 else if (!strcmp (option, "dont-free-domains"))
3686 mono_dont_free_domains = TRUE;
3687 else if (!strcmp (option, "dyn-runtime-invoke"))
3688 mini_debug_options.dyn_runtime_invoke = TRUE;
3689 else if (!strcmp (option, "gdb"))
3690 mini_debug_options.gdb = TRUE;
3691 else if (!strcmp (option, "lldb"))
3692 mini_debug_options.lldb = TRUE;
3693 else if (!strcmp (option, "llvm-disable-self-init"))
3694 mini_debug_options.llvm_disable_self_init = TRUE;
3695 else if (!strcmp (option, "llvm-disable-inlining"))
3696 mini_debug_options.llvm_disable_inlining = TRUE;
3697 else if (!strcmp (option, "explicit-null-checks"))
3698 mini_debug_options.explicit_null_checks = TRUE;
3699 else if (!strcmp (option, "gen-seq-points"))
3700 mini_debug_options.gen_sdb_seq_points = TRUE;
3701 else if (!strcmp (option, "gen-compact-seq-points"))
3702 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3703 else if (!strcmp (option, "no-compact-seq-points"))
3704 mini_debug_options.no_seq_points_compact_data = TRUE;
3705 else if (!strcmp (option, "single-imm-size"))
3706 mini_debug_options.single_imm_size = TRUE;
3707 else if (!strcmp (option, "init-stacks"))
3708 mini_debug_options.init_stacks = TRUE;
3709 else if (!strcmp (option, "casts"))
3710 mini_debug_options.better_cast_details = TRUE;
3711 else if (!strcmp (option, "soft-breakpoints"))
3712 mini_debug_options.soft_breakpoints = TRUE;
3713 else if (!strcmp (option, "check-pinvoke-callconv"))
3714 mini_debug_options.check_pinvoke_callconv = TRUE;
3715 else if (!strcmp (option, "use-fallback-tls"))
3716 mini_debug_options.use_fallback_tls = TRUE;
3717 else if (!strcmp (option, "debug-domain-unload"))
3718 mono_enable_debug_domain_unload (TRUE);
3719 else if (!strcmp (option, "partial-sharing"))
3720 mono_set_partial_sharing_supported (TRUE);
3721 else if (!strcmp (option, "align-small-structs"))
3722 mono_align_small_structs = TRUE;
3723 else if (!strcmp (option, "native-debugger-break"))
3724 mini_debug_options.native_debugger_break = TRUE;
3725 else if (!strcmp (option, "disable_omit_fp"))
3726 mini_debug_options.disable_omit_fp = TRUE;
3727 // This is an internal testing feature.
3728 // Every tail. encountered is required to be optimized.
3729 // It is asserted.
3730 else if (!strcmp (option, "test-tailcall-require"))
3731 mini_debug_options.test_tailcall_require = TRUE;
3732 else if (!strcmp (option, "verbose-gdb"))
3733 mini_debug_options.verbose_gdb = TRUE;
3734 else if (!strcmp (option, "clr-memory-model"))
3735 // FIXME Kill this debug flag
3736 mini_debug_options.weak_memory_model = FALSE;
3737 else if (!strcmp (option, "weak-memory-model"))
3738 mini_debug_options.weak_memory_model = TRUE;
3739 else if (!strncmp (option, "thread-dump-dir=", 16))
3740 mono_set_thread_dump_dir(g_strdup(option + 16));
3741 else if (!strncmp (option, "aot-skip=", 9)) {
3742 mini_debug_options.aot_skip_set = TRUE;
3743 mini_debug_options.aot_skip = atoi (option + 9);
3744 } else
3745 return FALSE;
3747 return TRUE;
3750 static void
3751 mini_parse_debug_options (void)
3753 char *options = g_getenv ("MONO_DEBUG");
3754 gchar **args, **ptr;
3756 if (!options)
3757 return;
3759 args = g_strsplit (options, ",", -1);
3760 g_free (options);
3762 for (ptr = args; ptr && *ptr; ptr++) {
3763 const char *arg = *ptr;
3765 if (!mini_parse_debug_option (arg)) {
3766 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3767 // test-tailcall-require is also accepted but not documented.
3768 // empty string is also accepted and ignored as a consequence
3769 // of appending ",foo" without checking for empty.
3770 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', 'weak-memory-model'.\n");
3771 exit (1);
3775 g_strfreev (args);
3778 MonoDebugOptions *
3779 mini_get_debug_options (void)
3781 return &mini_debug_options;
3784 static gpointer
3785 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3787 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3788 gpointer* desc = NULL;
3790 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3791 return desc;
3792 #if defined(__mono_ppc64__)
3793 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3795 desc [0] = addr;
3796 desc [1] = NULL;
3797 desc [2] = NULL;
3798 # endif
3799 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3800 return desc;
3801 #else
3802 return addr;
3803 #endif
3806 static gpointer
3807 mini_get_addr_from_ftnptr (gpointer descr)
3809 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3810 return *(gpointer*)descr;
3811 #else
3812 return descr;
3813 #endif
3816 static void
3817 register_jit_stats (void)
3819 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3820 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3821 mono_counters_register ("Methods from AOT+LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot_llvm);
3822 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3823 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3824 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
3825 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_method_to_ir);
3826 mono_counters_register ("JIT/liveness_handle_exception_clauses", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3827 mono_counters_register ("JIT/handle_out_of_line_bblock", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_out_of_line_bblock);
3828 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_long_opts);
3829 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_typechecks);
3830 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop);
3831 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_emulate_ops);
3832 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches);
3833 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs);
3834 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce);
3835 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_alias_analysis);
3836 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_if_conversion);
3837 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_bb_ordering);
3838 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compile_dominator_info);
3839 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compute_natural_loops);
3840 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_insert_safepoints);
3841 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_compute);
3842 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_cprop);
3843 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_deadce);
3844 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_perform_abc_removal);
3845 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_remove);
3846 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop2);
3847 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs2);
3848 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce2);
3849 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches2);
3850 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_vtype_opts);
3851 mono_counters_register ("JIT/decompose_array_access_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_array_access_opts);
3852 mono_counters_register ("JIT/liveness_handle_exception_clauses2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3853 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_analyze_liveness);
3854 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_linear_scan);
3855 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_arch_allocate_vars);
3856 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_spill_global_vars);
3857 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop3);
3858 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce3);
3859 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_codegen);
3860 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_create_jit_info);
3861 mono_counters_register ("JIT/gc_create_gc_map", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_gc_create_gc_map);
3862 mono_counters_register ("JIT/save_seq_point_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_save_seq_point_info);
3863 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_time);
3864 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3865 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3866 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3867 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3868 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3869 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3870 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3871 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3872 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3873 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3874 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3875 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3876 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3877 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3878 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3879 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3880 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3881 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3884 static void runtime_invoke_info_free (gpointer value);
3886 static gint
3887 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3889 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3890 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3892 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3895 static guint
3896 class_method_pair_hash (gconstpointer data)
3898 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3900 return (gsize)pair->klass ^ (gsize)pair->method;
3903 static void
3904 mini_create_jit_domain_info (MonoDomain *domain)
3906 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3908 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3909 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3910 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3911 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3912 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3913 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3914 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3915 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3916 mono_jit_code_hash_init (&info->interp_code_hash);
3918 domain->runtime_info = info;
3921 static void
3922 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3924 MonoJumpList *jlist = (MonoJumpList *)value;
3925 g_slist_free ((GSList*)jlist->list);
3928 static void
3929 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3931 GSList *list = (GSList *)value;
3932 g_slist_free (list);
3935 static void
3936 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3938 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3939 mono_code_manager_destroy (di->code_mp);
3940 g_free (di);
3943 static void
3944 runtime_invoke_info_free (gpointer value)
3946 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3948 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3949 if (info->dyn_call_info)
3950 mono_arch_dyn_call_free (info->dyn_call_info);
3951 #endif
3952 g_free (info);
3955 static void
3956 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3958 g_slist_free ((GSList*)value);
3961 static void
3962 mini_free_jit_domain_info (MonoDomain *domain)
3964 MonoJitDomainInfo *info = domain_jit_info (domain);
3966 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3967 g_hash_table_destroy (info->jump_target_hash);
3968 if (info->jump_target_got_slot_hash) {
3969 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3970 g_hash_table_destroy (info->jump_target_got_slot_hash);
3972 if (info->dynamic_code_hash) {
3973 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3974 g_hash_table_destroy (info->dynamic_code_hash);
3976 g_hash_table_destroy (info->method_code_hash);
3977 g_hash_table_destroy (info->jump_trampoline_hash);
3978 g_hash_table_destroy (info->jit_trampoline_hash);
3979 g_hash_table_destroy (info->delegate_trampoline_hash);
3980 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3981 g_hash_table_destroy (info->mrgctx_hash);
3982 g_hash_table_destroy (info->method_rgctx_hash);
3983 g_hash_table_destroy (info->interp_method_pointer_hash);
3984 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3985 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3986 g_hash_table_destroy (info->seq_points);
3987 g_hash_table_destroy (info->arch_seq_points);
3988 if (info->agent_info)
3989 mini_get_dbg_callbacks ()->free_domain_info (domain);
3990 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3991 if (info->llvm_jit_callees) {
3992 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3993 g_hash_table_destroy (info->llvm_jit_callees);
3995 mono_internal_hash_table_destroy (&info->interp_code_hash);
3996 #ifdef ENABLE_LLVM
3997 mono_llvm_free_domain_info (domain);
3998 #endif
4000 g_free (domain->runtime_info);
4001 domain->runtime_info = NULL;
4004 #ifdef ENABLE_LLVM
4005 static gboolean
4006 llvm_init_inner (void)
4008 if (!mono_llvm_load (NULL))
4009 return FALSE;
4011 mono_llvm_init ();
4012 return TRUE;
4014 #endif
4017 * mini_llvm_init:
4019 * Load and initialize LLVM support.
4020 * Return TRUE on success.
4022 gboolean
4023 mini_llvm_init (void)
4025 #ifdef ENABLE_LLVM
4026 static gboolean llvm_inited;
4027 static gboolean init_result;
4029 mono_loader_lock_if_inited ();
4030 if (!llvm_inited) {
4031 init_result = llvm_init_inner ();
4032 llvm_inited = TRUE;
4034 mono_loader_unlock_if_inited ();
4035 return init_result;
4036 #else
4037 return FALSE;
4038 #endif
4041 void
4042 mini_add_profiler_argument (const char *desc)
4044 if (!profile_options)
4045 profile_options = g_ptr_array_new ();
4047 g_ptr_array_add (profile_options, (gpointer) desc);
4051 const MonoEECallbacks *mono_interp_callbacks_pointer;
4053 void
4054 mini_install_interp_callbacks (const MonoEECallbacks *cbs)
4056 mono_interp_callbacks_pointer = cbs;
4059 static MonoDebuggerCallbacks dbg_cbs;
4061 void
4062 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4064 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4065 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4068 MonoDebuggerCallbacks*
4069 mini_get_dbg_callbacks (void)
4071 return &dbg_cbs;
4075 mono_ee_api_version (void)
4077 return MONO_EE_API_VERSION;
4080 void
4081 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4083 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4086 void
4087 mono_interp_to_native_trampoline (gpointer addr, gpointer ccontext)
4089 mini_get_interp_callbacks ()->to_native_trampoline (addr, ccontext);
4092 static gboolean
4093 mini_is_interpreter_enabled (void)
4095 return mono_use_interpreter;
4098 static const char*
4099 mono_get_runtime_build_version (void);
4101 MonoDomain *
4102 mini_init (const char *filename, const char *runtime_version)
4104 ERROR_DECL (error);
4105 MonoDomain *domain;
4107 MonoRuntimeCallbacks callbacks;
4109 static const MonoThreadInfoRuntimeCallbacks ticallbacks = {
4110 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK, mono)
4113 MONO_VES_INIT_BEGIN ();
4115 CHECKED_MONO_INIT ();
4117 #if defined(__linux__)
4118 if (access ("/proc/self/maps", F_OK) != 0) {
4119 g_print ("Mono requires /proc to be mounted.\n");
4120 exit (1);
4122 #endif
4124 mono_interp_stub_init ();
4125 #ifndef DISABLE_INTERPRETER
4126 if (mono_use_interpreter)
4127 mono_ee_interp_init (mono_interp_opts_string);
4128 #endif
4130 mono_debugger_agent_stub_init ();
4131 #ifndef DISABLE_SDB
4132 mono_debugger_agent_init ();
4133 #endif
4135 if (sdb_options)
4136 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4138 mono_os_mutex_init_recursive (&jit_mutex);
4140 mono_cross_helpers_run ();
4142 mono_counters_init ();
4144 mini_jit_init ();
4146 mini_jit_init_job_control ();
4148 /* Happens when using the embedding interface */
4149 if (!default_opt_set)
4150 default_opt = mono_parse_default_optimizations (NULL);
4152 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4153 if (mono_aot_only)
4154 mono_set_generic_sharing_vt_supported (TRUE);
4155 #else
4156 if (mono_llvm_only)
4157 mono_set_generic_sharing_vt_supported (TRUE);
4158 #endif
4160 mono_tls_init_runtime_keys ();
4162 if (!global_codeman)
4163 global_codeman = mono_code_manager_new ();
4165 memset (&callbacks, 0, sizeof (callbacks));
4166 callbacks.create_ftnptr = mini_create_ftnptr;
4167 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4168 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4169 callbacks.get_runtime_build_version = mono_get_runtime_build_version;
4170 callbacks.set_cast_details = mono_set_cast_details;
4171 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4172 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4173 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4174 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4175 callbacks.imt_entry_inited = mini_imt_entry_inited;
4176 callbacks.init_delegate = mini_init_delegate;
4177 #define JIT_INVOKE_WORKS
4178 #ifdef JIT_INVOKE_WORKS
4179 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4180 #endif
4181 #define JIT_TRAMPOLINES_WORK
4182 #ifdef JIT_TRAMPOLINES_WORK
4183 callbacks.compile_method = mono_jit_compile_method;
4184 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4185 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4186 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4187 callbacks.free_method = mono_jit_free_method;
4188 #ifndef DISABLE_REMOTING
4189 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4190 #endif
4191 #endif
4192 #ifndef DISABLE_REMOTING
4193 if (mono_use_interpreter)
4194 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4195 #endif
4196 callbacks.is_interpreter_enabled = mini_is_interpreter_enabled;
4197 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4199 #ifndef DISABLE_CRASH_REPORTING
4200 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4201 #endif
4203 mono_install_callbacks (&callbacks);
4205 #ifndef HOST_WIN32
4206 mono_w32handle_init ();
4207 #endif
4209 mono_thread_info_runtime_init (&ticallbacks);
4211 if (g_hasenv ("MONO_DEBUG")) {
4212 mini_parse_debug_options ();
4215 mono_code_manager_init ();
4217 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4219 static const MonoCodeManagerCallbacks code_manager_callbacks = {
4221 #undef MONO_CODE_MANAGER_CALLBACK
4222 #define MONO_CODE_MANAGER_CALLBACK(ret, name, sig) mono_arch_code_ ## name,
4223 MONO_CODE_MANAGER_CALLBACKS
4227 mono_code_manager_install_callbacks (&code_manager_callbacks);
4228 #endif
4230 mono_hwcap_init ();
4232 mono_arch_cpu_init ();
4234 mono_arch_init ();
4236 mono_unwind_init ();
4238 if (mini_debug_options.lldb || g_hasenv ("MONO_LLDB")) {
4239 mono_lldb_init ("");
4240 mono_dont_free_domains = TRUE;
4243 #ifdef XDEBUG_ENABLED
4244 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4245 if (mono_xdebug) {
4246 mono_xdebug_init (mono_xdebug);
4247 g_free (mono_xdebug);
4248 /* So methods for multiple domains don't have the same address */
4249 mono_dont_free_domains = TRUE;
4250 mono_using_xdebug = TRUE;
4251 } else if (mini_debug_options.gdb) {
4252 mono_xdebug_init ((char*)"gdb");
4253 mono_dont_free_domains = TRUE;
4254 mono_using_xdebug = TRUE;
4256 #endif
4258 #ifdef ENABLE_LLVM
4259 if (mono_use_llvm) {
4260 if (!mono_llvm_load (NULL)) {
4261 mono_use_llvm = FALSE;
4262 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4265 if (mono_use_llvm)
4266 mono_llvm_init ();
4267 #endif
4269 mono_trampolines_init ();
4271 if (default_opt & MONO_OPT_AOT)
4272 mono_aot_init ();
4274 mini_get_dbg_callbacks ()->init ();
4276 #ifdef TARGET_WASM
4277 mono_wasm_debugger_init ();
4278 #endif
4280 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4281 mono_set_generic_sharing_supported (TRUE);
4282 #endif
4284 mono_thread_info_signals_init ();
4286 mono_init_native_crash_info ();
4288 #ifndef MONO_CROSS_COMPILE
4289 mono_runtime_install_handlers ();
4290 #endif
4291 mono_threads_install_cleanup (mini_thread_cleanup);
4293 #ifdef JIT_TRAMPOLINES_WORK
4294 mono_install_create_domain_hook (mini_create_jit_domain_info);
4295 mono_install_free_domain_hook (mini_free_jit_domain_info);
4296 #endif
4297 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4298 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4299 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4301 mono_profiler_state.context_enable = mini_profiler_context_enable;
4302 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4303 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4304 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4305 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4306 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4308 if (profile_options)
4309 for (guint i = 0; i < profile_options->len; i++)
4310 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4312 mono_profiler_started ();
4314 if (mini_debug_options.collect_pagefault_stats)
4315 mono_aot_set_make_unreadable (TRUE);
4317 if (runtime_version)
4318 domain = mono_init_version (filename, runtime_version);
4319 else
4320 domain = mono_init_from_assembly (filename, filename);
4322 if (mono_aot_only) {
4323 /* This helps catch code allocation requests */
4324 mono_code_manager_set_read_only (domain->code_mp);
4325 mono_marshal_use_aot_wrappers (TRUE);
4328 if (mono_llvm_only) {
4329 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline);
4330 mono_set_always_build_imt_trampolines (TRUE);
4331 } else if (mono_aot_only) {
4332 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4333 } else {
4334 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4337 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4338 mono_arch_finish_init ();
4340 /* This must come after mono_init () in the aot-only case */
4341 mono_exceptions_init ();
4343 /* This should come after mono_init () too */
4344 mini_gc_init ();
4346 mono_create_icall_signatures ();
4348 register_jit_stats ();
4350 #define JIT_CALLS_WORK
4351 #ifdef JIT_CALLS_WORK
4352 /* Needs to be called here since register_jit_icall depends on it */
4353 mono_marshal_init ();
4355 mono_arch_register_lowlevel_calls ();
4357 register_icalls ();
4359 mono_generic_sharing_init ();
4360 #endif
4362 #ifdef MONO_ARCH_SIMD_INTRINSICS
4363 mono_simd_intrinsics_init ();
4364 #endif
4366 mono_tasklets_init ();
4368 register_trampolines (domain);
4370 if (mono_compile_aot)
4372 * Avoid running managed code when AOT compiling, since the platform
4373 * might only support aot-only execution.
4375 mono_runtime_set_no_exec (TRUE);
4377 mono_mem_account_register_counters ();
4379 #define JIT_RUNTIME_WORKS
4380 #ifdef JIT_RUNTIME_WORKS
4381 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4382 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4383 mono_error_assert_ok (error);
4384 mono_thread_attach (domain);
4385 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4386 #endif
4388 #ifdef ENABLE_EXPERIMENT_TIERED
4389 if (!mono_compile_aot) {
4390 /* create compilation thread in background */
4391 mini_tiered_init ();
4393 #endif
4395 if (mono_profiler_sampling_enabled ())
4396 mono_runtime_setup_stat_profiler ();
4398 MONO_PROFILER_RAISE (runtime_initialized, ());
4400 MONO_VES_INIT_END ();
4402 return domain;
4405 static void
4406 register_icalls (void)
4408 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4409 ves_icall_get_frame_info);
4410 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4411 ves_icall_get_trace);
4412 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4413 mono_runtime_install_handlers);
4414 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4415 mono_runtime_cleanup_handlers);
4417 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4418 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4419 mini_get_dbg_callbacks ()->unhandled_exception);
4420 #endif
4423 * It's important that we pass `TRUE` as the last argument here, as
4424 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4425 * *did* emit a wrapper, we'd be looking at infinite recursion since
4426 * the wrapper would call the icall which would call the wrapper and
4427 * so on.
4429 register_icall (mono_profiler_raise_method_enter, mono_icall_sig_void_ptr_ptr, TRUE);
4430 register_icall (mono_profiler_raise_method_leave, mono_icall_sig_void_ptr_ptr, TRUE);
4431 register_icall (mono_profiler_raise_method_tail_call, mono_icall_sig_void_ptr_ptr, TRUE);
4432 register_icall (mono_profiler_raise_exception_clause, mono_icall_sig_void_ptr_int_int_object, TRUE);
4434 register_icall (mono_trace_enter_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4435 register_icall (mono_trace_leave_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4436 g_assert (mono_get_lmf_addr == mono_tls_get_lmf_addr);
4437 register_icall (mono_jit_set_domain, mono_icall_sig_void_ptr, TRUE);
4438 register_icall (mono_domain_get, mono_icall_sig_ptr, TRUE);
4440 register_icall (mono_llvm_throw_exception, mono_icall_sig_void_object, TRUE);
4441 register_icall (mono_llvm_rethrow_exception, mono_icall_sig_void_object, TRUE);
4442 register_icall (mono_llvm_resume_exception, mono_icall_sig_void, TRUE);
4443 register_icall (mono_llvm_match_exception, mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
4444 register_icall (mono_llvm_clear_exception, NULL, TRUE);
4445 register_icall (mono_llvm_load_exception, mono_icall_sig_object, TRUE);
4446 register_icall (mono_llvm_throw_corlib_exception, mono_icall_sig_void_int, TRUE);
4447 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4448 register_icall (mono_llvm_set_unhandled_exception_handler, NULL, TRUE);
4450 // FIXME: This is broken
4451 #ifndef TARGET_WASM
4452 register_icall (mono_debug_personality, mono_icall_sig_int_int_int_ptr_ptr_ptr, TRUE);
4453 #endif
4454 #endif
4456 if (!mono_llvm_only) {
4457 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception, mono_icall_sig_void_object, TRUE);
4458 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception, mono_icall_sig_void_object, TRUE);
4459 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception, mono_icall_sig_void_ptr, TRUE);
4461 register_icall (mono_thread_get_undeniable_exception, mono_icall_sig_object, FALSE);
4462 register_icall (ves_icall_thread_finish_async_abort, mono_icall_sig_void, FALSE);
4463 register_icall (mono_thread_interruption_checkpoint, mono_icall_sig_object, FALSE);
4464 register_icall (mono_thread_force_interruption_checkpoint_noraise, mono_icall_sig_object, FALSE);
4466 register_icall (mono_threads_state_poll, mono_icall_sig_void, FALSE);
4468 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4469 register_opcode_emulation (OP_LMUL, __emul_lmul, mono_icall_sig_long_long_long, mono_llmult, FALSE);
4470 register_opcode_emulation (OP_LDIV, __emul_ldiv, mono_icall_sig_long_long_long, mono_lldiv, FALSE);
4471 register_opcode_emulation (OP_LDIV_UN, __emul_ldiv_un, mono_icall_sig_long_long_long, mono_lldiv_un, FALSE);
4472 register_opcode_emulation (OP_LREM, __emul_lrem, mono_icall_sig_long_long_long, mono_llrem, FALSE);
4473 register_opcode_emulation (OP_LREM_UN, __emul_lrem_un, mono_icall_sig_long_long_long, mono_llrem_un, FALSE);
4474 #endif
4475 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4476 register_opcode_emulation (OP_LMUL_OVF_UN, __emul_lmul_ovf_un, mono_icall_sig_long_long_long, mono_llmult_ovf_un, FALSE);
4477 register_opcode_emulation (OP_LMUL_OVF, __emul_lmul_ovf, mono_icall_sig_long_long_long, mono_llmult_ovf, FALSE);
4478 #endif
4480 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4481 register_opcode_emulation (OP_LSHL, __emul_lshl, mono_icall_sig_long_long_int32, mono_lshl, TRUE);
4482 register_opcode_emulation (OP_LSHR, __emul_lshr, mono_icall_sig_long_long_int32, mono_lshr, TRUE);
4483 register_opcode_emulation (OP_LSHR_UN, __emul_lshr_un, mono_icall_sig_long_long_int32, mono_lshr_un, TRUE);
4484 #endif
4486 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4487 register_opcode_emulation (OP_IDIV, __emul_op_idiv, mono_icall_sig_int32_int32_int32, mono_idiv, FALSE);
4488 register_opcode_emulation (OP_IDIV_UN, __emul_op_idiv_un, mono_icall_sig_int32_int32_int32, mono_idiv_un, FALSE);
4489 register_opcode_emulation (OP_IREM, __emul_op_irem, mono_icall_sig_int32_int32_int32, mono_irem, FALSE);
4490 register_opcode_emulation (OP_IREM_UN, __emul_op_irem_un, mono_icall_sig_int32_int32_int32, mono_irem_un, FALSE);
4491 #endif
4493 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4494 register_opcode_emulation (OP_IMUL, __emul_op_imul, mono_icall_sig_int32_int32_int32, mono_imul, TRUE);
4495 #endif
4497 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4498 register_opcode_emulation (OP_IMUL_OVF, __emul_op_imul_ovf, mono_icall_sig_int32_int32_int32, mono_imul_ovf, FALSE);
4499 register_opcode_emulation (OP_IMUL_OVF_UN, __emul_op_imul_ovf_un, mono_icall_sig_int32_int32_int32, mono_imul_ovf_un, FALSE);
4500 #endif
4502 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4503 register_opcode_emulation (OP_FDIV, __emul_fdiv, mono_icall_sig_double_double_double, mono_fdiv, FALSE);
4504 #endif
4506 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4507 register_opcode_emulation (OP_FCONV_TO_U8, __emul_fconv_to_u8, mono_icall_sig_ulong_double, mono_fconv_u8_2, FALSE);
4508 register_opcode_emulation (OP_RCONV_TO_U8, __emul_rconv_to_u8, mono_icall_sig_ulong_float, mono_rconv_u8, FALSE);
4509 #endif
4510 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4511 register_opcode_emulation (OP_FCONV_TO_U4, __emul_fconv_to_u4, mono_icall_sig_uint32_double, mono_fconv_u4_2, FALSE);
4512 register_opcode_emulation (OP_RCONV_TO_U4, __emul_rconv_to_u4, mono_icall_sig_uint32_float, mono_rconv_u4, FALSE);
4513 #endif
4514 register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, FALSE);
4515 register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
4516 register_opcode_emulation (OP_FCONV_TO_OVF_U8_UN, __emul_fconv_to_ovf_u8_un, mono_icall_sig_ulong_double, mono_fconv_ovf_u8_un, FALSE);
4517 register_opcode_emulation (OP_RCONV_TO_OVF_I8, __emul_rconv_to_ovf_i8, mono_icall_sig_long_float, mono_rconv_ovf_i8, FALSE);
4518 register_opcode_emulation (OP_RCONV_TO_OVF_U8, __emul_rconv_to_ovf_u8, mono_icall_sig_ulong_float, mono_rconv_ovf_u8, FALSE);
4519 register_opcode_emulation (OP_RCONV_TO_OVF_U8_UN, __emul_rconv_to_ovf_u8_un, mono_icall_sig_ulong_float, mono_rconv_ovf_u8_un, FALSE);
4521 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4522 register_opcode_emulation (OP_FCONV_TO_I8, __emul_fconv_to_i8, mono_icall_sig_long_double, mono_fconv_i8, FALSE);
4523 register_opcode_emulation (OP_RCONV_TO_I8, __emul_rconv_to_i8, mono_icall_sig_long_float, mono_rconv_i8, FALSE);
4524 #endif
4526 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4527 register_opcode_emulation (OP_ICONV_TO_R_UN, __emul_iconv_to_r_un, mono_icall_sig_double_int32, mono_conv_to_r8_un, FALSE);
4528 #endif
4529 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4530 register_opcode_emulation (OP_LCONV_TO_R8, __emul_lconv_to_r8, mono_icall_sig_double_long, mono_lconv_to_r8, FALSE);
4531 #endif
4532 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4533 register_opcode_emulation (OP_LCONV_TO_R4, __emul_lconv_to_r4, mono_icall_sig_float_long, mono_lconv_to_r4, FALSE);
4534 #endif
4535 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4536 register_opcode_emulation (OP_LCONV_TO_R_UN, __emul_lconv_to_r8_un, mono_icall_sig_double_long, mono_lconv_to_r8_un, FALSE);
4537 #endif
4538 #ifdef MONO_ARCH_EMULATE_FREM
4539 register_opcode_emulation (OP_FREM, __emul_frem, mono_icall_sig_double_double_double, mono_fmod, FALSE);
4540 register_opcode_emulation (OP_RREM, __emul_rrem, mono_icall_sig_float_float_float, fmodf, FALSE);
4541 #endif
4543 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4544 if (mono_arch_is_soft_float ()) {
4545 register_opcode_emulation (OP_FSUB, __emul_fsub, mono_icall_sig_double_double_double, mono_fsub, FALSE);
4546 register_opcode_emulation (OP_FADD, __emul_fadd, mono_icall_sig_double_double_double, mono_fadd, FALSE);
4547 register_opcode_emulation (OP_FMUL, __emul_fmul, mono_icall_sig_double_double_double, mono_fmul, FALSE);
4548 register_opcode_emulation (OP_FNEG, __emul_fneg, mono_icall_sig_double_double, mono_fneg, FALSE);
4549 register_opcode_emulation (OP_ICONV_TO_R8, __emul_iconv_to_r8, mono_icall_sig_double_int32, mono_conv_to_r8, FALSE);
4550 register_opcode_emulation (OP_ICONV_TO_R4, __emul_iconv_to_r4, mono_icall_sig_double_int32, mono_conv_to_r4, FALSE);
4551 register_opcode_emulation (OP_FCONV_TO_R4, __emul_fconv_to_r4, mono_icall_sig_double_double, mono_fconv_r4, FALSE);
4552 register_opcode_emulation (OP_FCONV_TO_I1, __emul_fconv_to_i1, mono_icall_sig_int8_double, mono_fconv_i1, FALSE);
4553 register_opcode_emulation (OP_FCONV_TO_I2, __emul_fconv_to_i2, mono_icall_sig_int16_double, mono_fconv_i2, FALSE);
4554 register_opcode_emulation (OP_FCONV_TO_I4, __emul_fconv_to_i4, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4555 register_opcode_emulation (OP_FCONV_TO_U1, __emul_fconv_to_u1, mono_icall_sig_uint8_double, mono_fconv_u1, FALSE);
4556 register_opcode_emulation (OP_FCONV_TO_U2, __emul_fconv_to_u2, mono_icall_sig_uint16_double, mono_fconv_u2, FALSE);
4558 #if TARGET_SIZEOF_VOID_P == 4
4559 register_opcode_emulation (OP_FCONV_TO_I, __emul_fconv_to_i, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4560 #endif
4562 register_opcode_emulation (OP_FBEQ, __emul_fcmp_eq, mono_icall_sig_uint32_double_double, mono_fcmp_eq, FALSE);
4563 register_opcode_emulation (OP_FBLT, __emul_fcmp_lt, mono_icall_sig_uint32_double_double, mono_fcmp_lt, FALSE);
4564 register_opcode_emulation (OP_FBGT, __emul_fcmp_gt, mono_icall_sig_uint32_double_double, mono_fcmp_gt, FALSE);
4565 register_opcode_emulation (OP_FBLE, __emul_fcmp_le, mono_icall_sig_uint32_double_double, mono_fcmp_le, FALSE);
4566 register_opcode_emulation (OP_FBGE, __emul_fcmp_ge, mono_icall_sig_uint32_double_double, mono_fcmp_ge, FALSE);
4567 register_opcode_emulation (OP_FBNE_UN, __emul_fcmp_ne_un, mono_icall_sig_uint32_double_double, mono_fcmp_ne_un, FALSE);
4568 register_opcode_emulation (OP_FBLT_UN, __emul_fcmp_lt_un, mono_icall_sig_uint32_double_double, mono_fcmp_lt_un, FALSE);
4569 register_opcode_emulation (OP_FBGT_UN, __emul_fcmp_gt_un, mono_icall_sig_uint32_double_double, mono_fcmp_gt_un, FALSE);
4570 register_opcode_emulation (OP_FBLE_UN, __emul_fcmp_le_un, mono_icall_sig_uint32_double_double, mono_fcmp_le_un, FALSE);
4571 register_opcode_emulation (OP_FBGE_UN, __emul_fcmp_ge_un, mono_icall_sig_uint32_double_double, mono_fcmp_ge_un, FALSE);
4573 register_opcode_emulation (OP_FCEQ, __emul_fcmp_ceq, mono_icall_sig_uint32_double_double, mono_fceq, FALSE);
4574 register_opcode_emulation (OP_FCGT, __emul_fcmp_cgt, mono_icall_sig_uint32_double_double, mono_fcgt, FALSE);
4575 register_opcode_emulation (OP_FCGT_UN, __emul_fcmp_cgt_un, mono_icall_sig_uint32_double_double, mono_fcgt_un, FALSE);
4576 register_opcode_emulation (OP_FCLT, __emul_fcmp_clt, mono_icall_sig_uint32_double_double, mono_fclt, FALSE);
4577 register_opcode_emulation (OP_FCLT_UN, __emul_fcmp_clt_un, mono_icall_sig_uint32_double_double, mono_fclt_un, FALSE);
4579 register_icall (mono_fload_r4, mono_icall_sig_double_ptr, FALSE);
4580 register_icall (mono_fstore_r4, mono_icall_sig_void_double_ptr, FALSE);
4581 register_icall (mono_fload_r4_arg, mono_icall_sig_uint32_double, FALSE);
4582 register_icall (mono_isfinite_double, mono_icall_sig_int32_double, FALSE);
4584 #endif
4585 register_icall (mono_ckfinite, mono_icall_sig_double_double, FALSE);
4587 #ifdef COMPRESSED_INTERFACE_BITMAP
4588 register_icall (mono_class_interface_match, mono_icall_sig_uint32_ptr_int32, TRUE);
4589 #endif
4591 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4592 #if SIZEOF_REGISTER == 4
4593 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_uint32_double, mono_fconv_u4, TRUE);
4594 #else
4595 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_ulong_double, mono_fconv_u8, TRUE);
4596 #endif
4598 /* other jit icalls */
4599 register_icall (ves_icall_mono_delegate_ctor, mono_icall_sig_void_object_object_ptr, FALSE);
4600 register_icall (ves_icall_mono_delegate_ctor_interp, mono_icall_sig_void_object_object_ptr, FALSE);
4601 register_icall (mono_class_static_field_address,
4602 mono_icall_sig_ptr_ptr_ptr, FALSE);
4603 register_icall (mono_ldtoken_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4604 register_icall (mono_ldtoken_wrapper_generic_shared,
4605 mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4606 register_icall (mono_get_special_static_data, mono_icall_sig_ptr_int, FALSE);
4607 register_icall (ves_icall_mono_ldstr, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4608 register_icall (mono_helper_stelem_ref_check, mono_icall_sig_void_object_object, FALSE);
4609 register_icall (ves_icall_object_new, mono_icall_sig_object_ptr_ptr, FALSE);
4610 register_icall (ves_icall_object_new_specific, mono_icall_sig_object_ptr, FALSE);
4611 register_icall (ves_icall_array_new, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4612 register_icall (ves_icall_array_new_specific, mono_icall_sig_object_ptr_int32, FALSE);
4613 register_icall (ves_icall_runtime_class_init, mono_icall_sig_void_ptr, FALSE);
4614 register_icall (mono_ldftn, mono_icall_sig_ptr_ptr, FALSE);
4615 register_icall (mono_ldvirtfn, mono_icall_sig_ptr_object_ptr, FALSE);
4616 register_icall (mono_ldvirtfn_gshared, mono_icall_sig_ptr_object_ptr, FALSE);
4617 register_icall (mono_helper_compile_generic_method, mono_icall_sig_ptr_object_ptr_ptr, FALSE);
4618 register_icall (mono_helper_ldstr, mono_icall_sig_object_ptr_int, FALSE);
4619 register_icall (mono_helper_ldstr_mscorlib, mono_icall_sig_object_int, FALSE);
4620 register_icall (mono_helper_newobj_mscorlib, mono_icall_sig_object_int, FALSE);
4621 register_icall (mono_value_copy_internal, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
4622 register_icall (mono_object_castclass_unbox, mono_icall_sig_object_object_ptr, FALSE);
4623 register_icall (mono_break, NULL, TRUE);
4624 register_icall (mono_create_corlib_exception_0, mono_icall_sig_object_int, TRUE);
4625 register_icall (mono_create_corlib_exception_1, mono_icall_sig_object_int_object, TRUE);
4626 register_icall (mono_create_corlib_exception_2, mono_icall_sig_object_int_object_object, TRUE);
4627 register_icall (mono_array_new_1, mono_icall_sig_object_ptr_int, FALSE);
4628 register_icall (mono_array_new_2, mono_icall_sig_object_ptr_int_int, FALSE);
4629 register_icall (mono_array_new_3, mono_icall_sig_object_ptr_int_int_int, FALSE);
4630 register_icall (mono_array_new_4, mono_icall_sig_object_ptr_int_int_int_int, FALSE);
4631 register_icall (mono_array_new_n_icall, mono_icall_sig_object_ptr_int_ptr, FALSE);
4632 register_icall (mono_get_native_calli_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4633 register_icall (mono_resume_unwind, mono_icall_sig_void_ptr, TRUE);
4634 register_icall (mono_gsharedvt_constrained_call, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr, FALSE);
4635 register_icall (mono_gsharedvt_value_copy, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4637 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4638 MonoRangeCopyFunction const mono_gc_wbarrier_range_copy = mono_gc_get_range_copy_func ();
4639 register_icall_no_wrapper (mono_gc_wbarrier_range_copy, mono_icall_sig_void_ptr_ptr_int);
4641 register_icall (mono_object_castclass_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4642 register_icall (mono_object_isinst_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4643 register_icall (mono_generic_class_init, mono_icall_sig_void_ptr, FALSE);
4644 register_icall (mono_fill_class_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4645 register_icall (mono_fill_method_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4647 register_dyn_icall (mini_get_dbg_callbacks ()->user_break, mono_debugger_agent_user_break, mono_icall_sig_void, FALSE);
4649 register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_int, TRUE);
4650 register_icall (mini_llvm_init_gshared_method_this, mono_icall_sig_void_ptr_int_object, TRUE);
4651 register_icall (mini_llvm_init_gshared_method_mrgctx, mono_icall_sig_void_ptr_int_ptr, TRUE);
4652 register_icall (mini_llvm_init_gshared_method_vtable, mono_icall_sig_void_ptr_int_ptr, TRUE);
4654 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4655 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4656 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call, mono_icall_sig_ptr_ptr_int_ptr);
4657 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call, mono_icall_sig_ptr_ptr_int_ptr);
4658 /* This needs a wrapper so it can have a preserveall cconv */
4659 register_icall (mini_llvmonly_init_vtable_slot, mono_icall_sig_ptr_ptr_int, FALSE);
4660 register_icall (mini_llvmonly_init_delegate, mono_icall_sig_void_object, TRUE);
4661 register_icall (mini_llvmonly_init_delegate_virtual, mono_icall_sig_void_object_object_ptr, TRUE);
4662 register_icall (mini_llvmonly_throw_nullref_exception, mono_icall_sig_void, TRUE);
4664 register_icall (mono_get_assembly_object, mono_icall_sig_object_ptr, TRUE);
4665 register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE);
4666 register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE);
4667 register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE);
4668 register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void);
4670 register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);
4671 register_icall_with_wrapper (mono_monitor_enter_v4_internal, mono_icall_sig_void_obj_ptr);
4672 register_icall_no_wrapper (mono_monitor_enter_fast, mono_icall_sig_int_obj);
4673 register_icall_no_wrapper (mono_monitor_enter_v4_fast, mono_icall_sig_int_obj_ptr);
4675 #ifdef TARGET_IOS
4676 register_icall (pthread_getspecific, mono_icall_sig_ptr_ptr, TRUE);
4677 #endif
4678 /* Register tls icalls */
4679 register_icall_no_wrapper (mono_tls_get_thread_extern, mono_icall_sig_ptr);
4680 register_icall_no_wrapper (mono_tls_get_jit_tls_extern, mono_icall_sig_ptr);
4681 register_icall_no_wrapper (mono_tls_get_domain_extern, mono_icall_sig_ptr);
4682 register_icall_no_wrapper (mono_tls_get_sgen_thread_info_extern, mono_icall_sig_ptr);
4683 register_icall_no_wrapper (mono_tls_get_lmf_addr_extern, mono_icall_sig_ptr);
4685 register_icall_no_wrapper (mono_interp_entry_from_trampoline, mono_icall_sig_void_ptr_ptr);
4686 register_icall_no_wrapper (mono_interp_to_native_trampoline, mono_icall_sig_void_ptr_ptr);
4688 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4689 mono_arch_register_icall ();
4690 #endif
4693 MonoJitStats mono_jit_stats = {0};
4696 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4697 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4699 MONO_NO_SANITIZE_THREAD
4700 static void
4701 print_jit_stats (void)
4703 if (mono_jit_stats.enabled) {
4704 g_print ("Mono Jit statistics\n");
4705 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4706 mono_jit_stats.max_ratio_method);
4707 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4708 mono_jit_stats.biggest_method);
4710 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4711 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4712 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4713 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4714 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4715 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4716 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4717 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4719 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4720 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4721 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4723 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4724 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4725 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4726 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4728 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4729 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4730 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4731 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4732 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4733 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4734 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4735 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4737 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4738 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4739 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4741 g_free (mono_jit_stats.max_ratio_method);
4742 mono_jit_stats.max_ratio_method = NULL;
4743 g_free (mono_jit_stats.biggest_method);
4744 mono_jit_stats.biggest_method = NULL;
4748 #ifdef DISABLE_CLEANUP
4749 void
4750 mini_cleanup (MonoDomain *domain)
4752 print_jit_stats ();
4753 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4755 #else
4756 void
4757 mini_cleanup (MonoDomain *domain)
4759 if (mono_profiler_sampling_enabled ())
4760 mono_runtime_shutdown_stat_profiler ();
4762 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4764 #ifndef DISABLE_COM
4765 mono_cominterop_release_all_rcws ();
4766 #endif
4768 #ifndef MONO_CROSS_COMPILE
4770 * mono_domain_finalize () needs to be called early since it needs the
4771 * execution engine still fully working (it may invoke managed finalizers).
4773 mono_domain_finalize (domain, 2000);
4774 #endif
4776 /* This accesses metadata so needs to be called before runtime shutdown */
4777 print_jit_stats ();
4779 #ifndef MONO_CROSS_COMPILE
4780 mono_runtime_cleanup (domain);
4781 #endif
4783 #ifndef ENABLE_NETCORE
4784 mono_threadpool_cleanup ();
4785 #endif
4787 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4789 mono_profiler_cleanup ();
4791 if (profile_options)
4792 g_ptr_array_free (profile_options, TRUE);
4794 mono_icall_cleanup ();
4796 mono_runtime_cleanup_handlers ();
4798 #ifndef MONO_CROSS_COMPILE
4799 mono_domain_free (domain, TRUE);
4800 #endif
4801 free_jit_tls_data (mono_tls_get_jit_tls ());
4803 #ifdef ENABLE_LLVM
4804 if (mono_use_llvm)
4805 mono_llvm_cleanup ();
4806 #endif
4808 mono_aot_cleanup ();
4810 mono_trampolines_cleanup ();
4812 mono_unwind_cleanup ();
4814 mono_code_manager_destroy (global_codeman);
4815 g_free (vtable_trampolines);
4817 mini_jit_cleanup ();
4819 mini_get_interp_callbacks ()->cleanup ();
4821 mono_tramp_info_cleanup ();
4823 mono_arch_cleanup ();
4825 mono_generic_sharing_cleanup ();
4827 mono_cleanup_native_crash_info ();
4829 mono_cleanup ();
4831 mono_trace_cleanup ();
4833 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4835 if (mono_inject_async_exc_method)
4836 mono_method_desc_free (mono_inject_async_exc_method);
4838 mono_tls_free_keys ();
4840 mono_os_mutex_destroy (&jit_mutex);
4842 mono_code_manager_cleanup ();
4844 #ifndef HOST_WIN32
4845 mono_w32handle_cleanup ();
4846 #endif
4848 #endif
4850 void
4851 mono_set_defaults (int verbose_level, guint32 opts)
4853 mini_verbose = verbose_level;
4854 mono_set_optimizations (opts);
4857 void
4858 mono_disable_optimizations (guint32 opts)
4860 default_opt &= ~opts;
4863 void
4864 mono_set_optimizations (guint32 opts)
4866 default_opt = opts;
4867 default_opt_set = TRUE;
4868 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4869 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4870 #else
4871 if (mono_llvm_only)
4872 mono_set_generic_sharing_vt_supported (TRUE);
4873 #endif
4876 void
4877 mono_set_verbose_level (guint32 level)
4879 mini_verbose = level;
4882 static const char*
4883 mono_get_runtime_build_version (void)
4885 return FULL_VERSION;
4889 * mono_get_runtime_build_info:
4890 * The returned string is owned by the caller. The returned string
4891 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4892 * \returns the runtime version + build date in string format.
4894 char*
4895 mono_get_runtime_build_info (void)
4897 if (mono_build_date)
4898 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4899 else
4900 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4903 static void
4904 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4906 GHashTable *assemblies = (GHashTable*)user_data;
4907 MonoImage *image = mono_assembly_get_image_internal (ass);
4908 MonoMethod *method, *invoke;
4909 int i, count = 0;
4911 if (g_hash_table_lookup (assemblies, ass))
4912 return;
4914 g_hash_table_insert (assemblies, ass, ass);
4916 if (mini_verbose > 0)
4917 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4919 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4920 ERROR_DECL (error);
4922 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
4923 if (!method) {
4924 mono_error_cleanup (error); /* FIXME don't swallow the error */
4925 continue;
4927 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4928 continue;
4929 if (method->is_generic || mono_class_is_gtd (method->klass))
4930 continue;
4932 count++;
4933 if (mini_verbose > 1) {
4934 char * desc = mono_method_full_name (method, TRUE);
4935 g_print ("Compiling %d %s\n", count, desc);
4936 g_free (desc);
4938 mono_compile_method_checked (method, error);
4939 if (!is_ok (error)) {
4940 mono_error_cleanup (error); /* FIXME don't swallow the error */
4941 continue;
4943 if (strcmp (method->name, "Finalize") == 0) {
4944 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4945 mono_compile_method_checked (invoke, error);
4946 mono_error_assert_ok (error);
4948 #ifndef DISABLE_REMOTING
4949 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
4950 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
4951 mono_error_assert_ok (error);
4952 mono_compile_method_checked (invoke, error);
4953 mono_error_assert_ok (error);
4955 #endif
4958 /* Load and precompile referenced assemblies as well */
4959 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4960 mono_assembly_load_reference (image, i);
4961 if (image->references [i])
4962 mono_precompile_assembly (image->references [i], assemblies);
4966 void mono_precompile_assemblies ()
4968 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4970 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4972 g_hash_table_destroy (assemblies);
4976 * Used by LLVM.
4977 * Have to export this for AOT.
4979 void
4980 mono_personality (void)
4982 /* Not used */
4983 g_assert_not_reached ();
4986 static MonoBreakPolicy
4987 always_insert_breakpoint (MonoMethod *method)
4989 return MONO_BREAK_POLICY_ALWAYS;
4992 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4995 * mono_set_break_policy:
4996 * \param policy_callback the new callback function
4998 * Allow embedders to decide whether to actually obey breakpoint instructions
4999 * (both break IL instructions and \c Debugger.Break method calls), for example
5000 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5001 * untrusted or semi-trusted code.
5003 * \p policy_callback will be called every time a break point instruction needs to
5004 * be inserted with the method argument being the method that calls \c Debugger.Break
5005 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5006 * if it wants the breakpoint to not be effective in the given method.
5007 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5009 void
5010 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5012 if (policy_callback)
5013 break_policy_func = policy_callback;
5014 else
5015 break_policy_func = always_insert_breakpoint;
5018 gboolean
5019 mini_should_insert_breakpoint (MonoMethod *method)
5021 switch (break_policy_func (method)) {
5022 case MONO_BREAK_POLICY_ALWAYS:
5023 return TRUE;
5024 case MONO_BREAK_POLICY_NEVER:
5025 return FALSE;
5026 case MONO_BREAK_POLICY_ON_DBG:
5027 g_warning ("mdb no longer supported");
5028 return FALSE;
5029 default:
5030 g_warning ("Incorrect value returned from break policy callback");
5031 return FALSE;
5035 // Custom handlers currently only implemented by Windows.
5036 #ifndef HOST_WIN32
5037 gboolean
5038 mono_runtime_install_custom_handlers (const char *handlers)
5040 return FALSE;
5043 void
5044 mono_runtime_install_custom_handlers_usage (void)
5046 fprintf (stdout,
5047 "Custom Handlers:\n"
5048 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5049 " separated list of available handlers to install.\n"
5050 "\n"
5051 "No handlers supported on current platform.\n");
5053 #endif /* HOST_WIN32 */