[llvm] Define a separate symbol for the aot method info for every method. Pass this...
[mono-project.git] / mono / mini / mini-runtime.c
blob1d217a6c9d01844dec7bc743e71ad37306935707
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;
107 MonoMethodDesc *mono_stats_method_desc;
109 gboolean mono_compile_aot = FALSE;
110 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
111 gboolean mono_aot_only = FALSE;
112 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
113 gboolean mono_llvm_only = FALSE;
114 /* By default, don't require AOT but attempt to probe */
115 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NORMAL;
116 MonoEEFeatures mono_ee_features;
118 const char *mono_build_date;
119 gboolean mono_do_signal_chaining;
120 gboolean mono_do_crash_chaining;
121 int mini_verbose = 0;
124 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
125 * it can load AOT code compiled by LLVM.
127 gboolean mono_use_llvm = FALSE;
129 gboolean mono_use_fast_math = FALSE;
131 // Lists of whitelisted and blacklisted CPU features
132 MonoCPUFeatures mono_cpu_features_enabled = (MonoCPUFeatures)0;
134 #ifdef DISABLE_SIMD
135 MonoCPUFeatures mono_cpu_features_disabled = MONO_CPU_X86_FULL_SSEAVX_COMBINED;
136 #else
137 MonoCPUFeatures mono_cpu_features_disabled = (MonoCPUFeatures)0;
138 #endif
140 gboolean mono_use_interpreter = FALSE;
141 const char *mono_interp_opts_string = NULL;
143 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
144 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
145 static mono_mutex_t jit_mutex;
147 static MonoCodeManager *global_codeman;
149 MonoDebugOptions mini_debug_options;
150 char *sdb_options;
152 #ifdef VALGRIND_JIT_REGISTER_MAP
153 int valgrind_register;
154 #endif
155 GList* mono_aot_paths;
157 static GPtrArray *profile_options;
159 static GSList *tramp_infos;
160 GSList *mono_interp_only_classes;
162 static void register_icalls (void);
164 gboolean
165 mono_running_on_valgrind (void)
167 #ifndef HOST_WIN32
168 if (RUNNING_ON_VALGRIND){
169 #ifdef VALGRIND_JIT_REGISTER_MAP
170 valgrind_register = TRUE;
171 #endif
172 return TRUE;
173 } else
174 #endif
175 return FALSE;
178 void
179 mono_set_use_llvm (mono_bool use_llvm)
181 mono_use_llvm = (gboolean)use_llvm;
185 typedef struct {
186 void *ip;
187 MonoMethod *method;
188 } FindTrampUserData;
190 static void
191 find_tramp (gpointer key, gpointer value, gpointer user_data)
193 FindTrampUserData *ud = (FindTrampUserData*)user_data;
195 if (value == ud->ip)
196 ud->method = (MonoMethod*)key;
199 /* debug function */
200 char*
201 mono_get_method_from_ip (void *ip)
203 MonoJitInfo *ji;
204 MonoMethod *method;
205 char *method_name;
206 char *res;
207 MonoDomain *domain = mono_domain_get ();
208 MonoDebugSourceLocation *location;
209 FindTrampUserData user_data;
211 if (!domain)
212 domain = mono_get_root_domain ();
214 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
215 if (!ji) {
216 user_data.ip = ip;
217 user_data.method = NULL;
218 mono_domain_lock (domain);
219 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
220 mono_domain_unlock (domain);
221 if (user_data.method) {
222 char *mname = mono_method_full_name (user_data.method, TRUE);
223 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
224 g_free (mname);
225 return res;
227 else
228 return NULL;
229 } else if (ji->is_trampoline) {
230 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
231 return res;
234 method = jinfo_get_method (ji);
235 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
236 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
238 char *file_loc = NULL;
239 if (location)
240 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
242 const char *in_interp = ji->is_interp ? " interp" : "";
244 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);
246 mono_debug_free_source_location (location);
247 g_free (method_name);
248 g_free (file_loc);
250 return res;
254 * mono_pmip:
255 * \param ip an instruction pointer address
257 * This method is used from a debugger to get the name of the
258 * method at address \p ip. This routine is typically invoked from
259 * a debugger like this:
261 * (gdb) print mono_pmip ($pc)
263 * \returns the name of the method at address \p ip.
265 G_GNUC_UNUSED char *
266 mono_pmip (void *ip)
268 return mono_get_method_from_ip (ip);
272 * mono_print_method_from_ip:
273 * \param ip an instruction pointer address
275 * This method is used from a debugger to get the name of the
276 * method at address \p ip.
278 * This prints the name of the method at address \p ip in the standard
279 * output. Unlike \c mono_pmip which returns a string, this routine
280 * prints the value on the standard output.
282 MONO_ATTR_USED void
283 mono_print_method_from_ip (void *ip)
285 MonoJitInfo *ji;
286 char *method;
287 MonoDebugSourceLocation *source;
288 MonoDomain *domain = mono_domain_get ();
289 MonoDomain *target_domain = mono_domain_get ();
290 FindTrampUserData user_data;
291 MonoGenericSharingContext*gsctx;
292 const char *shared_type;
294 if (!domain)
295 domain = mono_get_root_domain ();
296 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
297 if (ji && ji->is_trampoline) {
298 MonoTrampInfo *tinfo = ji->d.tramp_info;
300 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
301 return;
304 if (!ji) {
305 user_data.ip = ip;
306 user_data.method = NULL;
307 mono_domain_lock (domain);
308 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
309 mono_domain_unlock (domain);
311 if (user_data.method) {
312 char *mname = mono_method_full_name (user_data.method, TRUE);
313 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
314 g_free (mname);
315 return;
318 g_print ("No method at %p\n", ip);
319 fflush (stdout);
320 return;
322 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
323 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
325 gsctx = mono_jit_info_get_generic_sharing_context (ji);
326 shared_type = "";
327 if (gsctx) {
328 if (gsctx->is_gsharedvt)
329 shared_type = "gsharedvt ";
330 else
331 shared_type = "gshared ";
334 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);
336 if (source)
337 g_print ("%s:%d\n", source->source_file, source->row);
338 fflush (stdout);
340 mono_debug_free_source_location (source);
341 g_free (method);
345 * mono_method_same_domain:
347 * Determine whenever two compiled methods are in the same domain, thus
348 * the address of the callee can be embedded in the caller.
350 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
352 MonoMethod *cmethod;
354 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
355 return FALSE;
358 * If the call was made from domain-neutral to domain-specific
359 * code, we can't patch the call site.
361 if (caller->domain_neutral && !callee->domain_neutral)
362 return FALSE;
364 cmethod = jinfo_get_method (caller);
365 if ((cmethod->klass == mono_defaults.appdomain_class) &&
366 (strstr (cmethod->name, "InvokeInDomain"))) {
367 /* The InvokeInDomain methods change the current appdomain */
368 return FALSE;
371 return TRUE;
375 * mono_global_codeman_reserve:
377 * Allocate code memory from the global code manager.
379 void *(mono_global_codeman_reserve) (int size)
381 void *ptr;
383 if (mono_aot_only)
384 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
386 if (!global_codeman) {
387 /* This can happen during startup */
388 global_codeman = mono_code_manager_new ();
389 return mono_code_manager_reserve (global_codeman, size);
391 else {
392 mono_jit_lock ();
393 ptr = mono_code_manager_reserve (global_codeman, size);
394 mono_jit_unlock ();
395 return ptr;
399 /* The callback shouldn't take any locks */
400 void
401 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
403 mono_jit_lock ();
404 mono_code_manager_foreach (global_codeman, func, user_data);
405 mono_jit_unlock ();
409 * mono_create_unwind_op:
411 * Create an unwind op with the given parameters.
413 MonoUnwindOp*
414 mono_create_unwind_op (int when, int tag, int reg, int val)
416 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
418 op->op = tag;
419 op->reg = reg;
420 op->val = val;
421 op->when = when;
423 return op;
426 MonoJumpInfoToken *
427 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
429 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
430 res->image = image;
431 res->token = token;
432 res->has_context = context != NULL;
433 if (context)
434 memcpy (&res->context, context, sizeof (MonoGenericContext));
436 return res;
439 MonoJumpInfoToken *
440 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
442 return mono_jump_info_token_new2 (mp, image, token, NULL);
446 * mono_tramp_info_create:
448 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
449 * of JI, and UNWIND_OPS.
451 MonoTrampInfo*
452 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
454 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
456 info->name = g_strdup (name);
457 info->code = code;
458 info->code_size = code_size;
459 info->ji = ji;
460 info->unwind_ops = unwind_ops;
462 return info;
465 void
466 mono_tramp_info_free (MonoTrampInfo *info)
468 g_free (info->name);
470 // FIXME: ji
471 mono_free_unwind_info (info->unwind_ops);
472 if (info->owns_uw_info)
473 g_free (info->uw_info);
474 g_free (info);
477 static void
478 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
480 MonoJitInfo *ji;
482 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
483 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
484 ji->d.tramp_info = info;
485 ji->is_trampoline = TRUE;
487 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
489 mono_jit_info_table_add (domain, ji);
493 * mono_tramp_info_register:
495 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
496 * INFO can be NULL.
497 * Frees INFO.
499 static void
500 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
502 MonoTrampInfo *copy;
504 if (!info)
505 return;
507 if (!domain)
508 domain = mono_get_root_domain ();
510 if (domain)
511 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
512 else
513 copy = g_new0 (MonoTrampInfo, 1);
515 copy->code = info->code;
516 copy->code_size = info->code_size;
517 copy->name = g_strdup (info->name);
519 if (info->unwind_ops) {
520 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
521 copy->owns_uw_info = TRUE;
522 if (domain) {
523 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
524 guint8 *temp = copy->uw_info;
525 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
526 memcpy (copy->uw_info, temp, copy->uw_info_len);
527 g_free (temp);
529 } else {
530 /* Trampolines from aot have the unwind ops already encoded */
531 copy->uw_info = info->uw_info;
532 copy->uw_info_len = info->uw_info_len;
535 mono_save_trampoline_xdebug_info (info);
536 mono_lldb_save_trampoline_info (info);
538 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
539 if (!aot)
540 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
541 #endif
543 if (!domain) {
544 /* If no root domain has been created yet, postpone the registration. */
545 mono_jit_lock ();
546 tramp_infos = g_slist_prepend (tramp_infos, copy);
547 mono_jit_unlock ();
548 } else if (copy->uw_info) {
549 /* Only register trampolines that have unwind infos */
550 register_trampoline_jit_info (domain, copy);
553 if (mono_jit_map_is_enabled ())
554 mono_emit_jit_tramp (info->code, info->code_size, info->name);
556 mono_tramp_info_free (info);
559 void
560 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
562 mono_tramp_info_register_internal (info, domain, FALSE);
565 void
566 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
568 mono_tramp_info_register_internal (info, domain, TRUE);
571 static void
572 mono_tramp_info_cleanup (void)
574 GSList *l;
576 for (l = tramp_infos; l; l = l->next) {
577 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
579 mono_tramp_info_free (info);
581 g_slist_free (tramp_infos);
584 /* Register trampolines created before the root domain was created in the jit info tables */
585 static void
586 register_trampolines (MonoDomain *domain)
588 GSList *l;
590 for (l = tramp_infos; l; l = l->next) {
591 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
593 register_trampoline_jit_info (domain, info);
597 G_GNUC_UNUSED static void
598 break_count (void)
603 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
604 * Set a breakpoint in break_count () to break the last time <x> is done.
606 G_GNUC_UNUSED gboolean
607 mono_debug_count (void)
609 static int count = 0, int_val = 0;
610 static gboolean inited, has_value = FALSE;
612 count ++;
614 if (!inited) {
615 char *value = g_getenv ("COUNT");
616 if (value) {
617 int_val = atoi (value);
618 g_free (value);
619 has_value = TRUE;
621 inited = TRUE;
624 if (!has_value)
625 return TRUE;
627 if (count == int_val)
628 break_count ();
630 if (count > int_val)
631 return FALSE;
633 return TRUE;
636 MonoMethod*
637 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
639 /* This icall is used to check for exceptions, so don't check in the wrapper */
640 gboolean check_exc = (callinfo != &mono_get_jit_icall_info ()->mono_thread_interruption_checkpoint);
642 return mono_marshal_get_icall_wrapper (callinfo, check_exc);
645 gconstpointer
646 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
648 ERROR_DECL (error);
649 MonoMethod *wrapper;
650 gconstpointer addr, trampoline;
651 MonoDomain *domain = mono_get_root_domain ();
653 if (callinfo->wrapper)
654 return callinfo->wrapper;
656 wrapper = mono_icall_get_wrapper_method (callinfo);
658 if (do_compile) {
659 addr = mono_compile_method_checked (wrapper, error);
660 mono_error_assert_ok (error);
661 mono_memory_barrier ();
662 callinfo->wrapper = addr;
663 return addr;
664 } else {
665 if (callinfo->trampoline)
666 return callinfo->trampoline;
667 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
668 mono_error_assert_ok (error);
669 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
671 mono_loader_lock ();
672 if (!callinfo->trampoline) {
673 callinfo->trampoline = trampoline;
675 mono_loader_unlock ();
677 return callinfo->trampoline;
681 gconstpointer
682 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
684 return mono_icall_get_wrapper_full (callinfo, FALSE);
687 static MonoJitDynamicMethodInfo*
688 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
690 MonoJitDynamicMethodInfo *res;
692 if (domain_jit_info (domain)->dynamic_code_hash)
693 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
694 else
695 res = NULL;
696 return res;
699 #ifdef __cplusplus
700 template <typename T>
701 static void
702 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, T func, const char *symbol, gboolean no_wrapper)
703 #else
704 static void
705 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, gpointer func, const char *symbol, gboolean no_wrapper)
706 #endif
708 #ifndef DISABLE_JIT
709 mini_register_opcode_emulation (opcode, jit_icall_info, name, sig, func, symbol, no_wrapper);
710 #else
711 // FIXME ifdef in mini_register_opcode_emulation and just call it.
713 g_assert (!sig->hasthis);
714 g_assert (sig->param_count < 3);
716 mono_register_jit_icall_info (jit_icall_info, func, name, sig, no_wrapper, symbol);
717 #endif
720 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
721 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
724 * For JIT icalls implemented in C.
725 * NAME should be the same as the name of the C function whose address is FUNC.
726 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
727 * can't throw exceptions.
729 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
730 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
732 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
733 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
734 * must be extern "C".
736 #define register_icall(func, sig, avoid_wrapper) \
737 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
739 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
740 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
743 * Register an icall where FUNC is dynamically generated or otherwise not
744 * possible to link to it using NAME during AOT.
746 * func is an expression, such a local variable or a function call to get a function pointer.
747 * name is an identifier
749 * Providing func and name separately is what distinguishes "dyn" from regular.
751 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
753 #define register_dyn_icall(func, name, sig, save) \
754 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
756 MonoLMF *
757 mono_get_lmf (void)
759 MonoJitTlsData *jit_tls;
761 if ((jit_tls = mono_tls_get_jit_tls ()))
762 return jit_tls->lmf;
764 * We do not assert here because this function can be called from
765 * mini-gc.c on a thread that has not executed any managed code, yet
766 * (the thread object allocation can trigger a collection).
768 return NULL;
771 void
772 mono_set_lmf (MonoLMF *lmf)
774 (*mono_get_lmf_addr ()) = lmf;
777 static void
778 mono_set_jit_tls (MonoJitTlsData *jit_tls)
780 MonoThreadInfo *info;
782 mono_tls_set_jit_tls (jit_tls);
784 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
785 info = mono_thread_info_current ();
786 if (info)
787 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
790 static void
791 mono_set_lmf_addr (MonoLMF **lmf_addr)
793 MonoThreadInfo *info;
795 mono_tls_set_lmf_addr (lmf_addr);
797 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
798 info = mono_thread_info_current ();
799 if (info)
800 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
804 * mono_push_lmf:
806 * Push an MonoLMFExt frame on the LMF stack.
808 void
809 mono_push_lmf (MonoLMFExt *ext)
811 MonoLMF **lmf_addr;
813 lmf_addr = mono_get_lmf_addr ();
815 ext->lmf.previous_lmf = *lmf_addr;
816 /* Mark that this is a MonoLMFExt */
817 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
819 mono_set_lmf ((MonoLMF*)ext);
823 * mono_pop_lmf:
825 * Pop the last frame from the LMF stack.
827 void
828 mono_pop_lmf (MonoLMF *lmf)
830 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
834 * mono_jit_thread_attach:
836 * Called by Xamarin.Mac and other products. Attach thread to runtime if
837 * needed and switch to @domain.
839 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
841 * If the thread is newly-attached, put into GC Safe mode.
843 * @return the original domain which needs to be restored, or NULL.
845 MonoDomain*
846 mono_jit_thread_attach (MonoDomain *domain)
848 MonoDomain *orig;
849 gboolean attached;
851 if (!domain) {
852 /* Happens when called from AOTed code which is only used in the root domain. */
853 domain = mono_get_root_domain ();
856 g_assert (domain);
858 attached = mono_tls_get_jit_tls () != NULL;
860 if (!attached) {
861 mono_thread_attach (domain);
863 // #678164
864 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
866 /* mono_jit_thread_attach is external-only and not called by
867 * the runtime on any of our own threads. So if we get here,
868 * the thread is running native code - leave it in GC Safe mode
869 * and leave it to the n2m invoke wrappers or MONO_API entry
870 * points to switch to GC Unsafe.
872 MONO_STACKDATA (stackdata);
873 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
876 orig = mono_domain_get ();
877 if (orig != domain)
878 mono_domain_set_fast (domain, TRUE);
880 return orig != domain ? orig : NULL;
884 * mono_jit_set_domain:
886 * Set domain to @domain if @domain is not null
888 void
889 mono_jit_set_domain (MonoDomain *domain)
891 g_assert (!mono_threads_is_blocking_transition_enabled ());
893 if (domain)
894 mono_domain_set_fast (domain, TRUE);
898 * mono_thread_abort:
899 * \param obj exception object
900 * Abort the thread, print exception information and stack trace
902 static void
903 mono_thread_abort (MonoObject *obj)
905 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
907 /* handle_remove should be eventually called for this thread, too
908 g_free (jit_tls);*/
910 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
911 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
912 ((obj->vtable->klass) == mono_class_try_get_appdomain_unloaded_exception_class () &&
913 mono_thread_info_current ()->runtime_thread)) {
914 mono_thread_exit ();
915 } else {
916 mono_invoke_unhandled_exception_hook (obj);
920 static MonoJitTlsData*
921 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
923 MonoJitTlsData *jit_tls;
924 MonoLMF *lmf;
926 jit_tls = mono_tls_get_jit_tls ();
927 if (jit_tls)
928 return jit_tls;
930 jit_tls = g_new0 (MonoJitTlsData, 1);
932 jit_tls->abort_func = abort_func;
933 jit_tls->end_of_stack = stack_start;
935 mono_set_jit_tls (jit_tls);
937 lmf = g_new0 (MonoLMF, 1);
938 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
940 jit_tls->first_lmf = lmf;
942 mono_set_lmf_addr (&jit_tls->lmf);
944 jit_tls->lmf = lmf;
946 #ifdef MONO_ARCH_HAVE_TLS_INIT
947 mono_arch_tls_init ();
948 #endif
950 mono_setup_altstack (jit_tls);
952 return jit_tls;
955 static void
956 free_jit_tls_data (MonoJitTlsData *jit_tls)
958 //This happens during AOT cuz the thread is never attached
959 if (!jit_tls)
960 return;
961 mono_free_altstack (jit_tls);
963 if (jit_tls->interp_context)
964 mini_get_interp_callbacks ()->free_context (jit_tls->interp_context);
966 g_free (jit_tls->first_lmf);
967 g_free (jit_tls);
970 static void
971 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
973 MonoThreadInfo *thread;
974 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
975 thread = mono_thread_info_current_unchecked ();
976 if (thread)
977 thread->jit_data = jit_tls;
979 mono_arch_cpu_init ();
982 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
984 static void
985 mono_thread_abort_dummy (MonoObject *obj)
987 if (mono_thread_attach_aborted_cb)
988 mono_thread_attach_aborted_cb (obj);
989 else
990 mono_thread_abort (obj);
993 static void
994 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
996 MonoThreadInfo *thread;
997 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
998 thread = mono_thread_info_current_unchecked ();
999 if (thread)
1000 thread->jit_data = jit_tls;
1002 mono_arch_cpu_init ();
1005 static void
1006 mini_thread_cleanup (MonoNativeThreadId tid)
1008 MonoJitTlsData *jit_tls = NULL;
1009 MonoThreadInfo *info;
1011 info = mono_thread_info_current_unchecked ();
1013 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1014 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1015 * not a trivial thing.
1017 * The current offender is mono_thread_manage which cleanup threads from the outside.
1019 if (info && mono_thread_info_get_tid (info) == tid) {
1020 jit_tls = info->jit_data;
1021 info->jit_data = NULL;
1023 mono_set_jit_tls (NULL);
1025 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1026 if (mono_get_lmf ()) {
1027 mono_set_lmf (NULL);
1028 mono_set_lmf_addr (NULL);
1030 } else {
1031 info = mono_thread_info_lookup (tid);
1032 if (info) {
1033 jit_tls = info->jit_data;
1034 info->jit_data = NULL;
1036 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1039 if (jit_tls)
1040 free_jit_tls_data (jit_tls);
1043 MonoJumpInfo *
1044 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1046 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1048 ji->ip.i = ip;
1049 ji->type = type;
1050 ji->data.target = target;
1051 ji->next = list;
1053 return ji;
1056 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1058 static const char* const patch_info_str[] = {
1059 #define PATCH_INFO(a,b) "" #a,
1060 #include "patch-info.h"
1061 #undef PATCH_INFO
1064 const char*
1065 mono_ji_type_to_string (MonoJumpInfoType type)
1067 return patch_info_str [type];
1070 void
1071 mono_print_ji (const MonoJumpInfo *ji)
1073 const char *type = patch_info_str [ji->type];
1074 switch (ji->type) {
1075 case MONO_PATCH_INFO_RGCTX_FETCH:
1076 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1077 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1079 printf ("[%s ", type);
1080 mono_print_ji (entry->data);
1081 printf (" -> %s]", mono_rgctx_info_type_to_str (entry->info_type));
1082 break;
1084 case MONO_PATCH_INFO_METHOD:
1085 case MONO_PATCH_INFO_METHODCONST:
1086 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1087 char *s = mono_method_get_full_name (ji->data.method);
1088 printf ("[%s %s]", type, s);
1089 g_free (s);
1090 break;
1092 case MONO_PATCH_INFO_JIT_ICALL_ID:
1093 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji->data.jit_icall_id)->name);
1094 break;
1095 case MONO_PATCH_INFO_CLASS:
1096 case MONO_PATCH_INFO_VTABLE: {
1097 char *name = mono_class_full_name (ji->data.klass);
1098 printf ("[%s %s]", type, name);
1099 g_free (name);
1100 break;
1102 default:
1103 printf ("[%s]", type);
1104 break;
1108 #else
1110 const char*
1111 mono_ji_type_to_string (MonoJumpInfoType type)
1113 return "";
1116 void
1117 mono_print_ji (const MonoJumpInfo *ji)
1121 #endif
1124 * mono_patch_info_dup_mp:
1126 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1128 MonoJumpInfo*
1129 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1131 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1132 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1134 switch (patch_info->type) {
1135 case MONO_PATCH_INFO_RVA:
1136 case MONO_PATCH_INFO_LDSTR:
1137 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1138 case MONO_PATCH_INFO_LDTOKEN:
1139 case MONO_PATCH_INFO_DECLSEC:
1140 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1141 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1142 break;
1143 case MONO_PATCH_INFO_SWITCH:
1144 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1145 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1146 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1147 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1148 break;
1149 case MONO_PATCH_INFO_RGCTX_FETCH:
1150 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1151 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1152 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1153 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1154 break;
1155 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1156 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1157 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1158 break;
1159 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1160 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1161 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1162 break;
1163 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1164 MonoGSharedVtMethodInfo *info;
1165 MonoGSharedVtMethodInfo *oinfo;
1166 int i;
1168 oinfo = patch_info->data.gsharedvt_method;
1169 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1170 res->data.gsharedvt_method = info;
1171 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1172 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1173 for (i = 0; i < oinfo->num_entries; ++i) {
1174 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1175 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1177 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1179 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1180 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1181 break;
1183 case MONO_PATCH_INFO_VIRT_METHOD: {
1184 MonoJumpInfoVirtMethod *info;
1185 MonoJumpInfoVirtMethod *oinfo;
1187 oinfo = patch_info->data.virt_method;
1188 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1189 res->data.virt_method = info;
1190 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1191 break;
1193 default:
1194 break;
1197 return res;
1200 guint
1201 mono_patch_info_hash (gconstpointer data)
1203 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1204 const MonoJumpInfoType type = ji->type;
1205 guint hash = type << 8;
1207 switch (type) {
1208 case MONO_PATCH_INFO_RVA:
1209 case MONO_PATCH_INFO_LDSTR:
1210 case MONO_PATCH_INFO_LDTOKEN:
1211 case MONO_PATCH_INFO_DECLSEC:
1212 return hash | ji->data.token->token;
1213 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1214 return hash | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1215 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: // Hash on the selector name
1216 case MONO_PATCH_INFO_LDSTR_LIT:
1217 return g_str_hash (ji->data.name);
1218 case MONO_PATCH_INFO_VTABLE:
1219 case MONO_PATCH_INFO_CLASS:
1220 case MONO_PATCH_INFO_IID:
1221 case MONO_PATCH_INFO_ADJUSTED_IID:
1222 case MONO_PATCH_INFO_METHODCONST:
1223 case MONO_PATCH_INFO_METHOD:
1224 case MONO_PATCH_INFO_METHOD_JUMP:
1225 case MONO_PATCH_INFO_METHOD_FTNDESC:
1226 case MONO_PATCH_INFO_IMAGE:
1227 case MONO_PATCH_INFO_ICALL_ADDR:
1228 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1229 case MONO_PATCH_INFO_FIELD:
1230 case MONO_PATCH_INFO_SFLDA:
1231 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1232 case MONO_PATCH_INFO_METHOD_RGCTX:
1233 case MONO_PATCH_INFO_SIGNATURE:
1234 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1235 case MONO_PATCH_INFO_AOT_JIT_INFO:
1236 return hash | (gssize)ji->data.target;
1237 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1238 return hash | (gssize)ji->data.gsharedvt->method;
1239 case MONO_PATCH_INFO_RGCTX_FETCH:
1240 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1241 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1242 hash |= e->in_mrgctx | e->info_type | mono_patch_info_hash (e->data);
1243 if (e->in_mrgctx)
1244 return hash | (gssize)e->d.method;
1245 else
1246 return hash | (gssize)e->d.klass;
1248 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1249 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1250 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1251 case MONO_PATCH_INFO_GC_NURSERY_START:
1252 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1253 case MONO_PATCH_INFO_GOT_OFFSET:
1254 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1255 case MONO_PATCH_INFO_AOT_MODULE:
1256 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1257 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1258 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES:
1259 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE:
1260 return hash;
1261 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1262 return hash | ji->data.uindex;
1263 case MONO_PATCH_INFO_JIT_ICALL_ID:
1264 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1265 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1266 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1267 return hash | ji->data.index;
1268 case MONO_PATCH_INFO_SWITCH:
1269 return hash | ji->data.table->table_size;
1270 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1271 return hash | (gssize)ji->data.gsharedvt_method->method;
1272 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1273 return hash | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1274 case MONO_PATCH_INFO_VIRT_METHOD: {
1275 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1277 return hash | (gssize)info->klass | (gssize)info->method;
1279 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1280 return hash | mono_signature_hash (ji->data.sig);
1281 case MONO_PATCH_INFO_R8_GOT:
1282 return hash | (guint32)*(double*)ji->data.target;
1283 case MONO_PATCH_INFO_R4_GOT:
1284 return hash | (guint32)*(float*)ji->data.target;
1285 default:
1286 printf ("info type: %d\n", ji->type);
1287 mono_print_ji (ji); printf ("\n");
1288 g_assert_not_reached ();
1289 case MONO_PATCH_INFO_NONE:
1290 return 0;
1295 * mono_patch_info_equal:
1297 * This might fail to recognize equivalent patches, i.e. floats, so its only
1298 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1299 * in AOT.
1301 gint
1302 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1304 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1305 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1307 MonoJumpInfoType const ji1_type = ji1->type;
1308 MonoJumpInfoType const ji2_type = ji2->type;
1310 if (ji1_type != ji2_type)
1311 return 0;
1313 switch (ji1_type) {
1314 case MONO_PATCH_INFO_RVA:
1315 case MONO_PATCH_INFO_LDSTR:
1316 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1317 case MONO_PATCH_INFO_LDTOKEN:
1318 case MONO_PATCH_INFO_DECLSEC:
1319 return ji1->data.token->image == ji2->data.token->image &&
1320 ji1->data.token->token == ji2->data.token->token &&
1321 ji1->data.token->has_context == ji2->data.token->has_context &&
1322 ji1->data.token->context.class_inst == ji2->data.token->context.class_inst &&
1323 ji1->data.token->context.method_inst == ji2->data.token->context.method_inst;
1324 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1325 case MONO_PATCH_INFO_LDSTR_LIT:
1326 return g_str_equal (ji1->data.name, ji2->data.name);
1327 case MONO_PATCH_INFO_RGCTX_FETCH:
1328 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1329 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1330 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1332 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);
1334 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1335 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1336 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1338 return c1->sig == c2->sig && c1->method == c2->method;
1340 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1341 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1342 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1343 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;
1344 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1345 return ji1->data.uindex == ji2->data.uindex;
1346 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1347 return ji1->data.index == ji2->data.index;
1348 case MONO_PATCH_INFO_JIT_ICALL_ID:
1349 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1350 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1351 return ji1->data.jit_icall_id == ji2->data.jit_icall_id;
1352 case MONO_PATCH_INFO_VIRT_METHOD:
1353 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1354 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1355 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig);
1356 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1357 case MONO_PATCH_INFO_NONE:
1358 return 1;
1359 default:
1360 break;
1363 return ji1->data.target == ji2->data.target;
1366 gpointer
1367 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1369 unsigned char *ip = patch_info->ip.i + code;
1370 gconstpointer target = NULL;
1372 error_init (error);
1374 switch (patch_info->type) {
1375 case MONO_PATCH_INFO_BB:
1377 * FIXME: This could be hit for methods without a prolog. Should use -1
1378 * but too much code depends on a 0 initial value.
1380 //g_assert (patch_info->data.bb->native_offset);
1381 target = patch_info->data.bb->native_offset + code;
1382 break;
1383 case MONO_PATCH_INFO_ABS:
1384 target = patch_info->data.target;
1385 break;
1386 case MONO_PATCH_INFO_LABEL:
1387 target = patch_info->data.inst->inst_c0 + code;
1388 break;
1389 case MONO_PATCH_INFO_IP:
1390 target = ip;
1391 break;
1392 case MONO_PATCH_INFO_JIT_ICALL_ID: {
1393 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1394 target = mono_icall_get_wrapper (mi);
1395 break;
1397 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1398 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1399 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1400 target = mi->func;
1401 break;
1403 case MONO_PATCH_INFO_METHOD_JUMP:
1404 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1405 if (!is_ok (error))
1406 return NULL;
1407 break;
1408 case MONO_PATCH_INFO_METHOD:
1409 if (patch_info->data.method == method) {
1410 target = code;
1411 } else {
1412 /* get the trampoline to the method from the domain */
1413 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1414 if (!is_ok (error))
1415 return NULL;
1417 break;
1418 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1420 * Return an ftndesc for either AOTed code, or for an interp entry.
1422 target = mini_llvmonly_load_method_ftndesc (patch_info->data.method, FALSE, FALSE, error);
1423 return_val_if_nok (error, NULL);
1424 break;
1426 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1427 gpointer code_slot;
1429 mono_domain_lock (domain);
1430 if (!domain_jit_info (domain)->method_code_hash)
1431 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1432 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1433 if (!code_slot) {
1434 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1435 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1437 mono_domain_unlock (domain);
1438 target = code_slot;
1439 break;
1441 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1442 target = (gpointer)&mono_polling_required;
1443 break;
1444 case MONO_PATCH_INFO_SWITCH: {
1445 gpointer *jump_table;
1446 int i;
1447 if (method && method->dynamic) {
1448 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1449 } else {
1450 if (mono_aot_only) {
1451 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1452 } else {
1453 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1457 for (i = 0; i < patch_info->data.table->table_size; i++) {
1458 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1461 target = jump_table;
1462 break;
1464 case MONO_PATCH_INFO_METHODCONST:
1465 case MONO_PATCH_INFO_CLASS:
1466 case MONO_PATCH_INFO_IMAGE:
1467 case MONO_PATCH_INFO_FIELD:
1468 case MONO_PATCH_INFO_SIGNATURE:
1469 case MONO_PATCH_INFO_AOT_MODULE:
1470 target = patch_info->data.target;
1471 break;
1472 case MONO_PATCH_INFO_IID:
1473 mono_class_init_internal (patch_info->data.klass);
1474 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1475 break;
1476 case MONO_PATCH_INFO_ADJUSTED_IID:
1477 mono_class_init_internal (patch_info->data.klass);
1478 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1479 break;
1480 case MONO_PATCH_INFO_VTABLE:
1481 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1482 mono_error_assert_ok (error);
1483 break;
1484 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1485 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1487 if (del_tramp->is_virtual)
1488 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1489 else
1490 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1491 break;
1493 case MONO_PATCH_INFO_SFLDA: {
1494 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1495 mono_error_assert_ok (error);
1497 if (mono_class_field_is_special_static (patch_info->data.field)) {
1498 gpointer addr = NULL;
1500 mono_domain_lock (domain);
1501 if (domain->special_static_fields)
1502 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1503 mono_domain_unlock (domain);
1504 g_assert (addr);
1505 return addr;
1508 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (!method || mono_class_needs_cctor_run (vtable->klass, method)))
1509 /* Done by the generated code */
1511 else {
1512 if (run_cctors) {
1513 if (!mono_runtime_class_init_full (vtable, error)) {
1514 return NULL;
1518 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1519 break;
1521 case MONO_PATCH_INFO_RVA: {
1522 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1523 guint32 rva;
1525 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1526 target = mono_image_rva_map (patch_info->data.token->image, rva);
1527 break;
1529 case MONO_PATCH_INFO_R4:
1530 case MONO_PATCH_INFO_R4_GOT:
1531 case MONO_PATCH_INFO_R8:
1532 case MONO_PATCH_INFO_R8_GOT:
1533 target = patch_info->data.target;
1534 break;
1535 case MONO_PATCH_INFO_EXC_NAME:
1536 target = patch_info->data.name;
1537 break;
1538 case MONO_PATCH_INFO_LDSTR:
1539 target =
1540 mono_ldstr_checked (domain, patch_info->data.token->image,
1541 mono_metadata_token_index (patch_info->data.token->token), error);
1542 break;
1543 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1544 gpointer handle;
1545 MonoClass *handle_class;
1547 handle = mono_ldtoken_checked (patch_info->data.token->image,
1548 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1549 if (!is_ok (error))
1550 return NULL;
1551 mono_class_init_internal (handle_class);
1552 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType *)handle));
1554 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1555 if (!is_ok (error))
1556 return NULL;
1557 break;
1559 case MONO_PATCH_INFO_LDTOKEN: {
1560 gpointer handle;
1561 MonoClass *handle_class;
1563 handle = mono_ldtoken_checked (patch_info->data.token->image,
1564 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1565 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1566 mono_class_init_internal (handle_class);
1568 target = handle;
1569 break;
1571 case MONO_PATCH_INFO_DECLSEC:
1572 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1573 break;
1574 case MONO_PATCH_INFO_ICALL_ADDR:
1575 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1576 /* run_cctors == 0 -> AOT */
1577 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1578 if (run_cctors) {
1579 target = mono_lookup_pinvoke_call_internal (patch_info->data.method, error);
1580 if (!target) {
1581 if (mono_aot_only)
1582 return NULL;
1583 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));
1585 } else {
1586 target = NULL;
1588 } else {
1589 target = mono_lookup_internal_call (patch_info->data.method);
1591 if (mono_is_missing_icall_addr (target) && run_cctors)
1592 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1594 break;
1595 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1596 target = &mono_thread_interruption_request_flag;
1597 break;
1598 case MONO_PATCH_INFO_METHOD_RGCTX:
1599 target = mini_method_get_rgctx (patch_info->data.method);
1600 break;
1601 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1602 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1604 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1605 break;
1607 case MONO_PATCH_INFO_BB_OVF:
1608 case MONO_PATCH_INFO_EXC_OVF:
1609 case MONO_PATCH_INFO_GOT_OFFSET:
1610 case MONO_PATCH_INFO_NONE:
1611 break;
1612 case MONO_PATCH_INFO_RGCTX_FETCH: {
1613 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1615 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1616 break;
1618 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1619 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1620 if (!run_cctors)
1621 /* AOT, not needed */
1622 target = NULL;
1623 else
1624 target = mono_arch_get_seq_point_info (domain, code);
1625 break;
1626 #endif
1627 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1628 int card_table_shift_bits;
1629 gpointer card_table_mask;
1631 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1632 break;
1634 case MONO_PATCH_INFO_GC_NURSERY_START: {
1635 int shift_bits;
1636 size_t size;
1638 target = mono_gc_get_nursery (&shift_bits, &size);
1639 break;
1641 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1642 int shift_bits;
1643 size_t size;
1645 mono_gc_get_nursery (&shift_bits, &size);
1647 target = (gpointer)(gssize)shift_bits;
1648 break;
1650 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1651 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1652 break;
1654 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1655 target = NULL;
1656 break;
1658 case MONO_PATCH_INFO_LDSTR_LIT: {
1659 int len;
1660 char *s;
1662 len = strlen ((const char *)patch_info->data.target);
1663 s = (char *)mono_domain_alloc0 (domain, len + 1);
1664 memcpy (s, patch_info->data.target, len);
1665 target = s;
1667 break;
1669 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1670 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1671 break;
1672 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1673 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1674 break;
1676 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1677 target = (gpointer) &mono_profiler_state.exception_clause_count;
1678 break;
1680 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES:
1681 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINES_GOT_SLOTS_BASE: {
1682 /* Resolved in aot-runtime.c */
1683 g_assert_not_reached ();
1684 target = NULL;
1685 break;
1687 default:
1688 g_assert_not_reached ();
1691 return (gpointer)target;
1695 * mini_register_jump_site:
1697 * Register IP as a jump/tailcall site which calls METHOD.
1698 * This is needed because common_call_trampoline () cannot patch
1699 * the call site because the caller ip is not available for jumps.
1701 void
1702 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1704 MonoJumpList *jlist;
1706 MonoMethod *shared_method = mini_method_to_shared (method);
1707 method = shared_method ? shared_method : method;
1709 mono_domain_lock (domain);
1710 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1711 if (!jlist) {
1712 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1713 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1715 jlist->list = g_slist_prepend (jlist->list, ip);
1716 mono_domain_unlock (domain);
1720 * mini_patch_jump_sites:
1722 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1724 void
1725 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1727 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1729 if (!hash)
1730 return;
1732 MonoJumpInfo patch_info;
1733 MonoJumpList *jlist;
1734 GSList *tmp;
1736 /* The caller/callee might use different instantiations */
1737 MonoMethod *shared_method = mini_method_to_shared (method);
1738 method = shared_method ? shared_method : method;
1740 mono_domain_lock (domain);
1741 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1742 if (jlist)
1743 g_hash_table_remove (hash, method);
1744 mono_domain_unlock (domain);
1745 if (jlist) {
1746 patch_info.next = NULL;
1747 patch_info.ip.i = 0;
1748 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1749 patch_info.data.method = method;
1751 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1752 for (tmp = jlist->list; tmp; tmp = tmp->next)
1753 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1754 #else
1755 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1756 // for gshared methods
1757 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1758 ERROR_DECL (error);
1759 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1760 mono_error_assert_ok (error);
1762 #endif
1767 * mini_patch_llvm_jit_callees:
1769 * Patch function address slots used by llvm JITed code.
1771 void
1772 mini_patch_llvm_jit_callees (MonoDomain *domain, MonoMethod *method, gpointer addr)
1774 if (!domain_jit_info (domain)->llvm_jit_callees)
1775 return;
1776 GSList *callees = (GSList*)g_hash_table_lookup (domain_jit_info (domain)->llvm_jit_callees, method);
1777 GSList *l;
1779 for (l = callees; l; l = l->next) {
1780 gpointer *slot = (gpointer*)l->data;
1782 *slot = addr;
1786 void
1787 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1789 MonoGenericInst *inst;
1790 int i;
1792 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1794 if (context && context->class_inst) {
1795 inst = context->class_inst;
1796 for (i = 0; i < inst->type_argc; ++i) {
1797 MonoType *type = inst->type_argv [i];
1799 if (mini_is_gsharedvt_gparam (type))
1800 gsctx->is_gsharedvt = TRUE;
1803 if (context && context->method_inst) {
1804 inst = context->method_inst;
1806 for (i = 0; i < inst->type_argc; ++i) {
1807 MonoType *type = inst->type_argv [i];
1809 if (mini_is_gsharedvt_gparam (type))
1810 gsctx->is_gsharedvt = TRUE;
1816 * LOCKING: Acquires the jit code hash lock.
1818 MonoJitInfo*
1819 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1821 MonoJitInfo *ji;
1822 static gboolean inited = FALSE;
1823 static int lookups = 0;
1824 static int failed_lookups = 0;
1826 mono_domain_jit_code_hash_lock (domain);
1827 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1828 if (!ji && shared) {
1829 /* Try generic sharing */
1830 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1831 if (ji && !ji->has_generic_jit_info)
1832 ji = NULL;
1833 if (!inited) {
1834 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1835 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1836 inited = TRUE;
1839 ++lookups;
1840 if (!ji)
1841 ++failed_lookups;
1843 mono_domain_jit_code_hash_unlock (domain);
1845 return ji;
1848 static MonoJitInfo*
1849 lookup_method (MonoDomain *domain, MonoMethod *method)
1851 ERROR_DECL (error);
1852 MonoJitInfo *ji;
1853 MonoMethod *shared;
1855 ji = mini_lookup_method (domain, method, NULL);
1857 if (!ji) {
1858 if (!mono_method_is_generic_sharable (method, FALSE))
1859 return NULL;
1860 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1861 mono_error_assert_ok (error);
1862 ji = mini_lookup_method (domain, method, shared);
1865 return ji;
1868 MonoClass*
1869 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1871 ERROR_DECL (error);
1872 MonoClass *klass;
1874 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1875 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1876 if (context) {
1877 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1878 mono_error_cleanup (error); /* FIXME don't swallow the error */
1880 } else {
1881 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1882 mono_error_cleanup (error); /* FIXME don't swallow the error */
1884 if (klass)
1885 mono_class_init_internal (klass);
1886 return klass;
1889 #if ENABLE_JIT_MAP
1890 static FILE* perf_map_file;
1892 void
1893 mono_enable_jit_map (void)
1895 if (!perf_map_file) {
1896 char name [64];
1897 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1898 unlink (name);
1899 perf_map_file = fopen (name, "w");
1903 void
1904 mono_emit_jit_tramp (void *start, int size, const char *desc)
1906 if (perf_map_file)
1907 fprintf (perf_map_file, "%" PRIx64 " %x %s\n", (guint64)(gsize)start, size, desc);
1910 void
1911 mono_emit_jit_map (MonoJitInfo *jinfo)
1913 if (perf_map_file) {
1914 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1915 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1916 g_free (name);
1920 gboolean
1921 mono_jit_map_is_enabled (void)
1923 return perf_map_file != NULL;
1926 #endif
1928 #ifdef ENABLE_JIT_DUMP
1929 #include <sys/mman.h>
1930 #include <sys/syscall.h>
1931 #include <elf.h>
1933 static FILE *perf_dump_file;
1934 static mono_mutex_t perf_dump_mutex;
1935 static void *perf_dump_mmap_addr = MAP_FAILED;
1936 static guint32 perf_dump_pid;
1938 enum {
1939 JIT_DUMP_MAGIC = 0x4A695444,
1940 JIT_DUMP_VERSION = 2,
1941 #if HOST_X86
1942 ELF_MACHINE = EM_386,
1943 #elif HOST_AMD64
1944 ELF_MACHINE = EM_X86_64,
1945 #elif HOST_ARM
1946 ELF_MACHINE = EM_ARM,
1947 #elif HOST_ARM64
1948 ELF_MACHINE = EM_AARCH64,
1949 #elif HOST_POWERPC64
1950 ELF_MACHINE = EM_PPC64,
1951 #elif HOST_S390X
1952 ELF_MACHINE = EM_S390,
1953 #endif
1954 JIT_CODE_LOAD = 0
1956 typedef struct
1958 guint32 magic;
1959 guint32 version;
1960 guint32 total_size;
1961 guint32 elf_mach;
1962 guint32 pad1;
1963 guint32 pid;
1964 guint64 timestamp;
1965 guint64 flags;
1966 } FileHeader;
1967 typedef struct
1969 guint32 id;
1970 guint32 total_size;
1971 guint64 timestamp;
1972 } RecordHeader;
1973 typedef struct
1975 RecordHeader header;
1976 guint32 pid;
1977 guint32 tid;
1978 guint64 vma;
1979 guint64 code_addr;
1980 guint64 code_size;
1981 guint64 code_index;
1982 // Null terminated function name
1983 // Native code
1984 } JitCodeLoadRecord;
1986 static void add_file_header_info (FileHeader *header);
1987 static guint64 get_time_stamp_ns (void);
1988 static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record);
1990 void
1991 mono_enable_jit_dump (void)
1993 if (perf_dump_pid == 0)
1994 perf_dump_pid = getpid();
1996 if (!perf_dump_file) {
1997 char name [64];
1998 FileHeader header;
1999 memset (&header, 0, sizeof (header));
2001 mono_os_mutex_init (&perf_dump_mutex);
2002 mono_os_mutex_lock (&perf_dump_mutex);
2004 g_snprintf (name, sizeof (name), "/tmp/jit-%d.dump", perf_dump_pid);
2005 unlink (name);
2006 perf_dump_file = fopen (name, "w");
2008 add_file_header_info (&header);
2009 if (perf_dump_file) {
2010 fwrite (&header, sizeof (header), 1, perf_dump_file);
2011 //This informs perf of the presence of the jitdump file and support for the feature.​
2012 perf_dump_mmap_addr = mmap (NULL, sizeof (header), PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno (perf_dump_file), 0);
2015 mono_os_mutex_unlock (&perf_dump_mutex);
2019 static void
2020 add_file_header_info (FileHeader *header)
2022 header->magic = JIT_DUMP_MAGIC;
2023 header->version = JIT_DUMP_VERSION;
2024 header->total_size = sizeof (header);
2025 header->elf_mach = ELF_MACHINE;
2026 header->pad1 = 0;
2027 header->pid = perf_dump_pid;
2028 header->timestamp = get_time_stamp_ns ();
2029 header->flags = 0;
2032 static guint64
2033 get_time_stamp_ns (void)
2035 struct timespec ts;
2036 int result = clock_gettime (CLOCK_MONOTONIC, &ts);
2037 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
2040 void
2041 mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2043 static uint64_t code_index;
2045 if (perf_dump_file) {
2046 JitCodeLoadRecord record;
2047 size_t nameLen = strlen (jinfo->d.method->name);
2048 memset (&record, 0, sizeof (record));
2050 add_basic_JitCodeLoadRecord_info (&record);
2051 record.header.total_size = sizeof (record) + nameLen + 1 + jinfo->code_size;
2052 record.vma = (guint64)jinfo->code_start;
2053 record.code_addr = (guint64)jinfo->code_start;
2054 record.code_size = (guint64)jinfo->code_size;
2056 mono_os_mutex_lock (&perf_dump_mutex);
2058 record.code_index = ++code_index;
2060 // TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held).
2062 record.header.timestamp = get_time_stamp_ns ();
2064 fwrite (&record, sizeof (record), 1, perf_dump_file);
2065 fwrite (jinfo->d.method->name, nameLen + 1, 1, perf_dump_file);
2066 fwrite (code, jinfo->code_size, 1, perf_dump_file);
2068 mono_os_mutex_unlock (&perf_dump_mutex);
2072 static void
2073 add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record)
2075 record->header.id = JIT_CODE_LOAD;
2076 record->header.timestamp = get_time_stamp_ns ();
2077 record->pid = perf_dump_pid;
2078 record->tid = syscall (SYS_gettid);
2081 void
2082 mono_jit_dump_cleanup (void)
2084 if (perf_dump_mmap_addr != MAP_FAILED)
2085 munmap (perf_dump_mmap_addr, sizeof(FileHeader));
2086 if (perf_dump_file)
2087 fclose (perf_dump_file);
2090 #else
2092 void
2093 mono_enable_jit_dump (void)
2097 void
2098 mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2102 void
2103 mono_jit_dump_cleanup (void)
2107 #endif
2109 static void
2110 no_gsharedvt_in_wrapper (void)
2112 g_assert_not_reached ();
2116 Overall algorithm:
2118 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.
2119 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
2120 Dependency management in this case is too complex to justify implementing it.
2122 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
2124 TODO:
2125 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
2126 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
2127 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
2128 Maybe pool JitCompilationEntry, specially those with an inited cond var;
2130 typedef struct {
2131 MonoMethod *method;
2132 MonoDomain *domain;
2133 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
2134 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
2135 int threads_waiting; /* Number of threads waiting on this job */
2136 gboolean has_cond; /* True if @cond was initialized */
2137 gboolean done; /* True if the method finished JIT'ing */
2138 MonoCoopCond cond; /* Cond sleeping threads wait one */
2139 } JitCompilationEntry;
2141 typedef struct {
2142 GPtrArray *in_flight_methods; //JitCompilationEntry*
2143 MonoCoopMutex lock;
2144 } JitCompilationData;
2147 Timeout, in millisecounds, that we wait other threads to finish JITing.
2148 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.
2150 #define MAX_JIT_TIMEOUT_MS 1000
2153 static JitCompilationData compilation_data;
2154 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
2156 static void
2157 mini_jit_init_job_control (void)
2159 mono_coop_mutex_init (&compilation_data.lock);
2160 compilation_data.in_flight_methods = g_ptr_array_new ();
2163 static void
2164 lock_compilation_data (void)
2166 mono_coop_mutex_lock (&compilation_data.lock);
2169 static void
2170 unlock_compilation_data (void)
2172 mono_coop_mutex_unlock (&compilation_data.lock);
2175 static JitCompilationEntry*
2176 find_method (MonoMethod *method, MonoDomain *domain)
2178 int i;
2179 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
2180 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
2181 if (e->method == method && e->domain == domain)
2182 return e;
2185 return NULL;
2188 static void
2189 add_current_thread (MonoJitTlsData *jit_tls)
2191 ++jit_tls->active_jit_methods;
2194 static void
2195 unref_jit_entry (JitCompilationEntry *entry)
2197 --entry->ref_count;
2198 if (entry->ref_count)
2199 return;
2200 if (entry->has_cond)
2201 mono_coop_cond_destroy (&entry->cond);
2202 g_free (entry);
2206 * Returns true if this method waited successfully for another thread to JIT it
2208 static gboolean
2209 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2211 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2212 JitCompilationEntry *entry;
2214 static gboolean inited;
2215 if (!inited) {
2216 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2217 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2218 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2219 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2220 inited = TRUE;
2223 lock_compilation_data ();
2225 if (!(entry = find_method (method, domain))) {
2226 entry = g_new0 (JitCompilationEntry, 1);
2227 entry->method = method;
2228 entry->domain = domain;
2229 entry->compilation_count = entry->ref_count = 1;
2230 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2231 g_assert (find_method (method, domain) == entry);
2232 add_current_thread (jit_tls);
2234 unlock_compilation_data ();
2235 return FALSE;
2236 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2237 //We can't suspend the current thread if it's already JITing a method.
2238 //Dependency management is too compilated and we want to get rid of this anyways.
2240 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2241 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2243 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2244 ++entry->compilation_count;
2245 ++jit_methods_multiple;
2246 ++jit_tls->active_jit_methods;
2248 unlock_compilation_data ();
2249 return FALSE;
2250 } else {
2251 ++jit_methods_waited;
2252 ++entry->ref_count;
2254 if (!entry->has_cond) {
2255 mono_coop_cond_init (&entry->cond);
2256 entry->has_cond = TRUE;
2259 while (TRUE) {
2260 ++entry->threads_waiting;
2262 g_assert (entry->has_cond);
2263 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2264 --entry->threads_waiting;
2266 if (entry->done) {
2267 unref_jit_entry (entry);
2268 unlock_compilation_data ();
2269 return TRUE;
2270 } else {
2271 //We hit the timeout or a spurious wakeup, fallback to JITing
2272 g_assert (entry->ref_count > 1);
2273 unref_jit_entry (entry);
2274 ++jit_spurious_wakeups_or_timeouts;
2276 ++entry->compilation_count;
2277 ++jit_methods_multiple;
2278 ++jit_tls->active_jit_methods;
2280 unlock_compilation_data ();
2281 return FALSE;
2287 static void
2288 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2290 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2292 lock_compilation_data ();
2294 g_assert (jit_tls->active_jit_methods > 0);
2295 --jit_tls->active_jit_methods;
2297 JitCompilationEntry *entry = find_method (method, target_domain);
2298 g_assert (entry); // It would be weird to fail
2299 entry->done = TRUE;
2301 if (entry->threads_waiting) {
2302 g_assert (entry->has_cond);
2303 mono_coop_cond_broadcast (&entry->cond);
2306 if (--entry->compilation_count == 0) {
2307 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2308 unref_jit_entry (entry);
2311 unlock_compilation_data ();
2314 static MonoJitInfo*
2315 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2317 MonoDomain *domain = mono_get_root_domain ();
2318 MonoJitInfo *jinfo;
2319 guint8 *uw_info;
2320 guint32 info_len;
2322 if (info->uw_info) {
2323 uw_info = info->uw_info;
2324 info_len = info->uw_info_len;
2325 } else {
2326 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2329 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2330 jinfo->d.method = wrapper;
2331 jinfo->code_start = info->code;
2332 jinfo->code_size = info->code_size;
2333 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2335 if (!info->uw_info)
2336 g_free (uw_info);
2338 return jinfo;
2341 static gpointer
2342 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2344 MonoJitInfo *jinfo;
2345 gpointer code;
2347 if (mono_llvm_only) {
2348 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2349 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2351 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2353 * These wrappers are only created for signatures which are in the program, but
2354 * sometimes we load methods too eagerly and have to create them even if they
2355 * will never be called.
2357 return (gpointer)no_gsharedvt_in_wrapper;
2362 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2363 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2364 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2366 if (!piinfo->addr) {
2367 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2368 piinfo->addr = mono_lookup_internal_call (method);
2369 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2370 #ifdef HOST_WIN32
2371 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);
2372 #else
2373 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);
2374 #endif
2375 else {
2376 ERROR_DECL (ignored_error);
2377 mono_lookup_pinvoke_call_internal (method, ignored_error);
2378 mono_error_cleanup (ignored_error);
2382 MonoMethod *nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2383 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2384 return_val_if_nok (error, NULL);
2386 code = mono_get_addr_from_ftnptr (compiled_method);
2387 jinfo = mono_jit_info_table_find (target_domain, code);
2388 if (!jinfo)
2389 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2390 if (jinfo)
2391 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2392 return code;
2393 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2394 const char *name = method->name;
2395 char *full_name;
2396 MonoMethod *nm;
2398 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2399 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2400 MonoJitICallInfo *mi = &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor;
2402 * We need to make sure this wrapper
2403 * is compiled because it might end up
2404 * in an (M)RGCTX if generic sharing
2405 * is enabled, and would be called
2406 * indirectly. If it were a
2407 * trampoline we'd try to patch that
2408 * indirect call, which is not
2409 * possible.
2411 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2412 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2413 if (mono_llvm_only) {
2414 nm = mono_marshal_get_delegate_invoke (method, NULL);
2415 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2416 return_val_if_nok (error, NULL);
2417 return mono_get_addr_from_ftnptr (compiled_ptr);
2420 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2421 if (mono_use_interpreter)
2422 return NULL;
2424 return mono_create_delegate_trampoline (target_domain, method->klass);
2425 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2426 nm = mono_marshal_get_delegate_begin_invoke (method);
2427 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2428 return_val_if_nok (error, NULL);
2429 return mono_get_addr_from_ftnptr (compiled_ptr);
2430 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2431 nm = mono_marshal_get_delegate_end_invoke (method);
2432 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2433 return_val_if_nok (error, NULL);
2434 return mono_get_addr_from_ftnptr (compiled_ptr);
2438 full_name = mono_method_full_name (method, TRUE);
2439 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2440 g_free (full_name);
2441 return NULL;
2444 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2445 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2447 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2448 static MonoTrampInfo *in_tinfo, *out_tinfo;
2449 MonoTrampInfo *tinfo;
2450 MonoJitInfo *jinfo;
2451 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2453 if (is_in && in_tinfo)
2454 return in_tinfo->code;
2455 else if (!is_in && out_tinfo)
2456 return out_tinfo->code;
2459 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2460 * works.
2461 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2463 if (mono_ee_features.use_aot_trampolines)
2464 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2465 else
2466 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2467 jinfo = create_jit_info_for_trampoline (method, tinfo);
2468 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2469 if (is_in)
2470 in_tinfo = tinfo;
2471 else
2472 out_tinfo = tinfo;
2473 return tinfo->code;
2477 return NULL;
2480 static gpointer
2481 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2483 MonoDomain *target_domain, *domain = mono_domain_get ();
2484 MonoJitInfo *info;
2485 gpointer code = NULL, p;
2486 MonoJitICallInfo *callinfo = NULL;
2487 WrapperInfo *winfo = NULL;
2488 gboolean use_interp = FALSE;
2490 error_init (error);
2492 if (mono_ee_features.force_use_interpreter && !jit_only)
2493 use_interp = TRUE;
2494 if (!use_interp && mono_interp_only_classes) {
2495 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2496 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2497 use_interp = TRUE;
2500 if (use_interp) {
2501 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2502 if (code)
2503 return code;
2506 if (mono_llvm_only)
2507 /* Should be handled by the caller */
2508 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2511 * ICALL wrappers are handled specially, since there is only one copy of them
2512 * shared by all appdomains.
2514 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2515 winfo = mono_marshal_get_wrapper_info (method);
2516 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2517 callinfo = mono_find_jit_icall_info (winfo->d.icall.jit_icall_id);
2519 /* Must be domain neutral since there is only one copy */
2520 opt |= MONO_OPT_SHARED;
2521 } else {
2522 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2523 opt &= ~MONO_OPT_SHARED;
2526 if (opt & MONO_OPT_SHARED)
2527 target_domain = mono_get_root_domain ();
2528 else
2529 target_domain = domain;
2531 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2532 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2534 g_assert (info);
2535 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2536 MonoGenericContext *ctx = NULL;
2537 if (method->is_inflated)
2538 ctx = mono_method_get_context (method);
2539 method = info->d.synchronized_inner.method;
2540 if (ctx) {
2541 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2542 g_assert (is_ok (error)); /* FIXME don't swallow the error */
2547 lookup_start:
2548 info = lookup_method (target_domain, method);
2549 if (info) {
2550 /* We can't use a domain specific method in another domain */
2551 if (! ((domain != target_domain) && !info->domain_neutral)) {
2552 MonoVTable *vtable;
2554 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2555 vtable = mono_class_vtable_checked (domain, method->klass, error);
2556 if (!is_ok (error))
2557 return NULL;
2558 g_assert (vtable);
2559 if (!mono_runtime_class_init_full (vtable, error))
2560 return NULL;
2561 MONO_PROFILER_RAISE (jit_done, (method, info));
2562 return mono_create_ftnptr (target_domain, info->code_start);
2566 #ifdef MONO_USE_AOT_COMPILER
2567 if (opt & MONO_OPT_AOT) {
2568 MonoDomain *domain = NULL;
2570 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2571 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2572 g_assert (info);
2573 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2574 /* AOT'd wrappers for interp must be owned by root domain */
2575 domain = mono_get_root_domain ();
2578 if (!domain)
2579 domain = mono_domain_get ();
2581 mono_class_init_internal (method->klass);
2583 code = mono_aot_get_method (domain, method, error);
2584 if (code) {
2585 MonoVTable *vtable;
2587 if (mono_gc_is_critical_method (method)) {
2589 * The suspend code needs to be able to lookup these methods by ip in async context,
2590 * so preload their jit info.
2592 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2593 g_assert (ji);
2597 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2598 * This is not a problem, since it will be initialized when the method is first
2599 * called by init_method ().
2601 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2602 vtable = mono_class_vtable_checked (domain, method->klass, error);
2603 mono_error_assert_ok (error);
2604 if (!mono_runtime_class_init_full (vtable, error))
2605 return NULL;
2608 if (!is_ok (error))
2609 return NULL;
2611 #endif
2613 if (!code) {
2614 code = compile_special (method, target_domain, error);
2616 if (!is_ok (error))
2617 return NULL;
2620 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER) {
2621 if (mono_llvm_only) {
2622 /* Signal to the caller that AOTed code is not found */
2623 return NULL;
2625 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2627 if (!is_ok (error))
2628 return NULL;
2631 if (!code) {
2632 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2633 char *full_name = mono_type_get_full_name (method->klass);
2634 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2635 g_free (full_name);
2636 return NULL;
2639 if (mono_aot_only) {
2640 char *fullname = mono_method_get_full_name (method);
2641 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);
2642 g_free (fullname);
2644 return NULL;
2647 if (wait_or_register_method_to_compile (method, target_domain))
2648 goto lookup_start;
2649 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2650 unregister_method_for_compile (method, target_domain);
2652 if (!is_ok (error))
2653 return NULL;
2655 if (!code && mono_llvm_only) {
2656 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2657 g_assert_not_reached ();
2660 if (!code)
2661 return NULL;
2663 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2664 #ifndef HOST_WASM
2665 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2666 MonoDomain *d;
2669 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2671 MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2672 g_assert (ji);
2674 #endif
2676 p = mono_create_ftnptr (target_domain, code);
2678 if (callinfo) {
2679 // FIXME Locking here is somewhat historical due to mono_register_jit_icall_wrapper taking loader lock.
2680 // atomic_compare_exchange should suffice.
2681 mono_loader_lock ();
2682 mono_jit_lock ();
2683 if (!callinfo->wrapper) {
2684 callinfo->wrapper = p;
2686 mono_jit_unlock ();
2687 mono_loader_unlock ();
2690 // FIXME p or callinfo->wrapper or does not matter?
2691 return p;
2694 gpointer
2695 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2697 gpointer code;
2699 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2700 return code;
2704 * mono_jit_compile_method_jit_only:
2706 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2708 gpointer
2709 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2711 gpointer code;
2713 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2714 return code;
2717 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2718 static void
2719 invalidated_delegate_trampoline (char *desc)
2721 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2722 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2723 desc);
2725 #endif
2728 * mono_jit_free_method:
2730 * Free all memory allocated by the JIT for METHOD.
2732 static void
2733 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2735 MonoJitDynamicMethodInfo *ji;
2736 gboolean destroy = TRUE, removed;
2737 GHashTableIter iter;
2738 MonoJumpList *jlist;
2739 MonoJitDomainInfo *info = domain_jit_info (domain);
2741 g_assert (method->dynamic);
2743 if (mono_use_interpreter) {
2744 mini_get_interp_callbacks ()->free_method (domain, method);
2747 mono_domain_lock (domain);
2748 ji = mono_dynamic_code_hash_lookup (domain, method);
2749 mono_domain_unlock (domain);
2751 if (!ji)
2752 return;
2754 mono_debug_remove_method (method, domain);
2755 mono_lldb_remove_method (domain, method, ji);
2757 mono_domain_lock (domain);
2758 g_hash_table_remove (info->dynamic_code_hash, method);
2759 mono_domain_jit_code_hash_lock (domain);
2760 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2761 g_assert (removed);
2762 mono_domain_jit_code_hash_unlock (domain);
2763 g_hash_table_remove (info->jump_trampoline_hash, method);
2764 g_hash_table_remove (info->seq_points, method);
2766 ji->ji->seq_points = NULL;
2768 /* requires the domain lock - took above */
2769 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2771 /* Remove jump targets in this method */
2772 g_hash_table_iter_init (&iter, info->jump_target_hash);
2773 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2774 GSList *tmp, *remove;
2776 remove = NULL;
2777 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2778 guint8 *ip = (guint8 *)tmp->data;
2780 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2781 remove = g_slist_prepend (remove, tmp);
2783 for (tmp = remove; tmp; tmp = tmp->next) {
2784 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2786 g_slist_free (remove);
2788 mono_domain_unlock (domain);
2790 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2791 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2793 * Instead of freeing the code, change it to call an error routine
2794 * so people can fix their code.
2796 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2797 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2799 g_free (type);
2800 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2801 destroy = FALSE;
2803 #endif
2806 * This needs to be done before freeing code_mp, since the code address is the
2807 * key in the table, so if we free the code_mp first, another thread can grab the
2808 * same code address and replace our entry in the table.
2810 mono_jit_info_table_remove (domain, ji->ji);
2812 if (destroy)
2813 mono_code_manager_destroy (ji->code_mp);
2814 g_free (ji);
2817 gpointer
2818 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2820 gpointer code;
2821 MonoJitInfo *ji;
2823 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2824 if (!code) {
2825 ERROR_DECL (oerror);
2827 /* Might be AOTed code */
2828 mono_class_init_internal (method->klass);
2829 code = mono_aot_get_method (domain, method, oerror);
2830 if (code) {
2831 mono_error_assert_ok (oerror);
2832 ji = mono_jit_info_table_find (domain, code);
2833 } else {
2834 if (!is_ok (oerror))
2835 mono_error_cleanup (oerror);
2837 /* Might be interpreted */
2838 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2842 *out_ji = ji;
2844 return code;
2847 gpointer
2848 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2850 MonoDomain *target_domain;
2851 MonoJitInfo *info;
2853 if (default_opt & MONO_OPT_SHARED)
2854 target_domain = mono_get_root_domain ();
2855 else
2856 target_domain = domain;
2858 info = lookup_method (target_domain, method);
2859 if (info) {
2860 /* We can't use a domain specific method in another domain */
2861 if (! ((domain != target_domain) && !info->domain_neutral)) {
2862 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2863 if (ji)
2864 *ji = info;
2865 return info->code_start;
2869 if (ji)
2870 *ji = NULL;
2871 return NULL;
2874 static guint32 bisect_opt = 0;
2875 static GHashTable *bisect_methods_hash = NULL;
2877 void
2878 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2880 FILE *file;
2881 char method_name [2048];
2883 bisect_opt = opt;
2884 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2885 g_assert (bisect_methods_hash);
2887 file = fopen (method_list_filename, "r");
2888 g_assert (file);
2890 while (fgets (method_name, sizeof (method_name), file)) {
2891 size_t len = strlen (method_name);
2892 g_assert (len > 0);
2893 g_assert (method_name [len - 1] == '\n');
2894 method_name [len - 1] = 0;
2895 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2897 g_assert (feof (file));
2900 gboolean mono_do_single_method_regression = FALSE;
2901 guint32 mono_single_method_regression_opt = 0;
2902 MonoMethod *mono_current_single_method;
2903 GSList *mono_single_method_list;
2904 GHashTable *mono_single_method_hash;
2906 guint32
2907 mono_get_optimizations_for_method (MonoMethod *method, guint32 opt)
2909 g_assert (method);
2911 if (bisect_methods_hash) {
2912 char *name = mono_method_full_name (method, TRUE);
2913 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2914 g_free (name);
2915 if (res)
2916 return opt | bisect_opt;
2918 if (!mono_do_single_method_regression)
2919 return opt;
2920 if (!mono_current_single_method) {
2921 if (!mono_single_method_hash)
2922 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2923 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2924 g_hash_table_insert (mono_single_method_hash, method, method);
2925 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2927 return opt;
2929 if (method == mono_current_single_method)
2930 return mono_single_method_regression_opt;
2931 return opt;
2934 gpointer
2935 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2937 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2940 typedef struct {
2941 MonoMethod *method;
2942 gpointer compiled_method;
2943 gpointer runtime_invoke;
2944 MonoVTable *vtable;
2945 MonoDynCallInfo *dyn_call_info;
2946 MonoClass *ret_box_class;
2947 MonoMethodSignature *sig;
2948 gboolean gsharedvt_invoke;
2949 gboolean use_interp;
2950 gpointer *wrapper_arg;
2951 } RuntimeInvokeInfo;
2953 static RuntimeInvokeInfo*
2954 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2956 MonoMethod *invoke;
2957 RuntimeInvokeInfo *info = NULL;
2958 RuntimeInvokeInfo *ret = NULL;
2960 info = g_new0 (RuntimeInvokeInfo, 1);
2961 info->compiled_method = compiled_method;
2962 info->use_interp = use_interp;
2963 if (mono_llvm_only && method->string_ctor)
2964 info->sig = mono_marshal_get_string_ctor_signature (method);
2965 else
2966 info->sig = mono_method_signature_internal (method);
2968 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2969 (void)invoke;
2970 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2971 if (!is_ok (error))
2972 goto exit;
2973 g_assert (info->vtable);
2975 MonoMethodSignature *sig;
2976 sig = info->sig;
2977 MonoType *ret_type;
2980 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2981 * in full-aot mode, so we use a slower, but more generic wrapper if
2982 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2984 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2985 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2986 gboolean supported = TRUE;
2987 int i;
2989 if (method->string_ctor)
2990 sig = mono_marshal_get_string_ctor_signature (method);
2992 for (i = 0; i < sig->param_count; ++i) {
2993 MonoType *t = sig->params [i];
2995 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
2996 supported = FALSE;
2999 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
3000 supported = FALSE;
3002 if (supported) {
3003 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
3004 if (mini_debug_options.dyn_runtime_invoke)
3005 g_assert (info->dyn_call_info);
3008 #endif
3010 ret_type = sig->ret;
3011 switch (ret_type->type) {
3012 case MONO_TYPE_VOID:
3013 break;
3014 case MONO_TYPE_I1:
3015 case MONO_TYPE_U1:
3016 case MONO_TYPE_I2:
3017 case MONO_TYPE_U2:
3018 case MONO_TYPE_I4:
3019 case MONO_TYPE_U4:
3020 case MONO_TYPE_I:
3021 case MONO_TYPE_U:
3022 case MONO_TYPE_I8:
3023 case MONO_TYPE_U8:
3024 case MONO_TYPE_BOOLEAN:
3025 case MONO_TYPE_CHAR:
3026 case MONO_TYPE_R4:
3027 case MONO_TYPE_R8:
3028 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3029 break;
3030 case MONO_TYPE_PTR:
3031 info->ret_box_class = mono_defaults.int_class;
3032 break;
3033 case MONO_TYPE_STRING:
3034 case MONO_TYPE_CLASS:
3035 case MONO_TYPE_ARRAY:
3036 case MONO_TYPE_SZARRAY:
3037 case MONO_TYPE_OBJECT:
3038 break;
3039 case MONO_TYPE_GENERICINST:
3040 if (!MONO_TYPE_IS_REFERENCE (ret_type))
3041 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3042 break;
3043 case MONO_TYPE_VALUETYPE:
3044 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
3045 break;
3046 default:
3047 g_assert_not_reached ();
3048 break;
3051 if (info->use_interp) {
3052 ret = info;
3053 info = NULL;
3054 goto exit;
3057 if (!info->dyn_call_info) {
3058 if (mono_llvm_only) {
3059 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
3060 g_assert_not_reached ();
3061 #endif
3062 info->gsharedvt_invoke = TRUE;
3063 if (!callee_gsharedvt) {
3064 /* Invoke a gsharedvt out wrapper instead */
3065 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
3066 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
3068 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
3069 info->wrapper_arg [0] = mini_llvmonly_add_method_wrappers (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
3071 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
3072 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
3073 g_free (wrapper_sig);
3075 info->compiled_method = mono_jit_compile_method (wrapper, error);
3076 if (!is_ok (error))
3077 goto exit;
3078 } else {
3079 /* Gsharedvt methods can be invoked the same way */
3080 /* The out wrapper has the same signature as the compiled gsharedvt method */
3081 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
3083 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
3085 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
3086 g_free (wrapper_sig);
3089 info->runtime_invoke = mono_jit_compile_method (invoke, error);
3090 if (!is_ok (error))
3091 goto exit;
3094 ret = info;
3095 info = NULL;
3096 exit:
3097 g_free (info);
3098 return ret;
3101 static MonoObject*
3102 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
3104 MonoMethodSignature *sig = info->sig;
3105 MonoDomain *domain = mono_domain_get ();
3106 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
3107 gpointer retval_ptr;
3108 guint8 retval [256];
3109 int i, pindex;
3111 error_init (error);
3113 g_assert (info->gsharedvt_invoke);
3116 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
3117 * The advantage of this is the gsharedvt out wrappers have a reduced set of
3118 * signatures, so we only have to generate runtime invoke wrappers for these
3119 * signatures.
3120 * This code also handles invocation of gsharedvt methods directly, no
3121 * out wrappers are used in that case.
3123 // allocate param_refs = param_count and args = param_count + hasthis + 2.
3124 int const param_count = sig->param_count;
3125 gpointer* const param_refs = g_newa (gpointer, param_count * 2 + sig->hasthis + 2);
3126 gpointer* const args = param_refs + param_count;
3127 pindex = 0;
3129 * The runtime invoke wrappers expects pointers to primitive types, so have to
3130 * use indirections.
3132 if (sig->hasthis)
3133 args [pindex ++] = &obj;
3134 if (sig->ret->type != MONO_TYPE_VOID) {
3135 retval_ptr = &retval;
3136 args [pindex ++] = &retval_ptr;
3138 for (i = 0; i < sig->param_count; ++i) {
3139 MonoType *t = sig->params [i];
3141 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
3142 MonoClass *klass = mono_class_from_mono_type_internal (t);
3143 guint8 *nullable_buf;
3144 int size;
3146 size = mono_class_value_size (klass, NULL);
3147 nullable_buf = g_alloca (size);
3148 g_assert (nullable_buf);
3150 /* The argument pointed to by params [i] is either a boxed vtype or null */
3151 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
3152 params [i] = nullable_buf;
3155 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
3156 param_refs [i] = params [i];
3157 params [i] = &(param_refs [i]);
3159 args [pindex ++] = &params [i];
3161 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
3162 args [pindex ++] = &info->wrapper_arg;
3164 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3166 runtime_invoke (NULL, args, exc, info->compiled_method);
3167 if (exc && *exc)
3168 return NULL;
3170 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
3171 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3172 else
3173 return *(MonoObject**)retval;
3177 * mono_jit_runtime_invoke:
3178 * \param method: the method to invoke
3179 * \param obj: this pointer
3180 * \param params: array of parameter values.
3181 * \param exc: Set to the exception raised in the managed method.
3182 * \param error: error or caught exception object
3183 * If \p exc is NULL, \p error is thrown instead.
3184 * If coop is enabled, \p exc argument is ignored -
3185 * all exceptions are caught and propagated through \p error
3187 static MonoObject*
3188 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
3190 MonoMethod *invoke, *callee;
3191 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
3192 MonoDomain *domain = mono_domain_get ();
3193 MonoJitDomainInfo *domain_info;
3194 RuntimeInvokeInfo *info, *info2;
3195 MonoJitInfo *ji = NULL;
3196 gboolean callee_gsharedvt = FALSE;
3198 if (mono_ee_features.force_use_interpreter)
3199 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3201 error_init (error);
3202 if (exc)
3203 *exc = NULL;
3205 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
3206 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3207 return NULL;
3210 domain_info = domain_jit_info (domain);
3212 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3214 if (!info) {
3215 if (mono_security_core_clr_enabled ()) {
3217 * This might be redundant since mono_class_vtable () already does this,
3218 * but keep it just in case for moonlight.
3220 mono_class_setup_vtable (method->klass);
3221 if (mono_class_has_failure (method->klass)) {
3222 mono_error_set_for_class_failure (error, method->klass);
3223 if (exc)
3224 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3225 return NULL;
3229 gpointer compiled_method;
3231 callee = method;
3232 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3233 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3235 * Array Get/Set/Address methods. The JIT implements them using inline code
3236 * inside the runtime invoke wrappers, so no need to compile them.
3238 if (mono_aot_only) {
3240 * Call a wrapper, since the runtime invoke wrapper was not generated.
3242 MonoMethod *wrapper;
3244 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3245 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3246 callee = wrapper;
3247 } else {
3248 callee = NULL;
3252 gboolean use_interp = FALSE;
3254 if (callee) {
3255 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3256 if (!compiled_method) {
3257 g_assert (!is_ok (error));
3259 if (mono_use_interpreter)
3260 use_interp = TRUE;
3261 else
3262 return NULL;
3263 } else {
3264 if (mono_llvm_only) {
3265 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3266 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3267 if (callee_gsharedvt)
3268 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3271 if (!callee_gsharedvt)
3272 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3274 } else {
3275 compiled_method = NULL;
3278 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3279 if (!is_ok (error))
3280 return NULL;
3282 mono_domain_lock (domain);
3283 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3284 mono_domain_unlock (domain);
3285 if (info2) {
3286 g_free (info);
3287 info = info2;
3292 * We need this here because mono_marshal_get_runtime_invoke can place
3293 * the helper method in System.Object and not the target class.
3295 if (!mono_runtime_class_init_full (info->vtable, error)) {
3296 if (exc)
3297 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3298 return NULL;
3301 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3302 we always catch the exception and propagate it through the MonoError */
3303 gboolean catchExcInMonoError =
3304 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3305 MonoObject *invoke_exc = NULL;
3306 if (catchExcInMonoError)
3307 exc = &invoke_exc;
3309 /* The wrappers expect this to be initialized to NULL */
3310 if (exc)
3311 *exc = NULL;
3313 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3314 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3315 if (info->dyn_call_info) {
3316 if (!dyn_runtime_invoke) {
3317 mono_domain_lock (domain);
3319 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3320 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3321 if (!dyn_runtime_invoke && mono_use_interpreter) {
3322 info->use_interp = TRUE;
3323 info->dyn_call_info = NULL;
3324 } else if (!is_ok (error)) {
3325 mono_domain_unlock (domain);
3326 return NULL;
3328 mono_domain_unlock (domain);
3331 if (info->dyn_call_info) {
3332 MonoMethodSignature *sig = mono_method_signature_internal (method);
3333 gpointer *args;
3334 int i, pindex, buf_size;
3335 guint8 *buf;
3336 guint8 retval [256];
3338 /* Convert the arguments to the format expected by start_dyn_call () */
3339 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3340 pindex = 0;
3341 if (sig->hasthis)
3342 args [pindex ++] = &obj;
3343 for (i = 0; i < sig->param_count; ++i) {
3344 MonoType *t = sig->params [i];
3346 if (t->byref) {
3347 args [pindex ++] = &params [i];
3348 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3349 args [pindex ++] = &params [i];
3350 } else {
3351 args [pindex ++] = params [i];
3355 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3357 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3358 buf = g_alloca (buf_size);
3359 memset (buf, 0, buf_size);
3360 g_assert (buf);
3362 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3364 dyn_runtime_invoke (buf, exc, info->compiled_method);
3365 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3367 if (catchExcInMonoError && *exc != NULL) {
3368 mono_error_set_exception_instance (error, (MonoException*) *exc);
3369 return NULL;
3372 if (info->ret_box_class)
3373 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3374 else
3375 return *(MonoObject**)retval;
3377 #endif
3379 MonoObject *result;
3381 if (info->use_interp) {
3382 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3383 return_val_if_nok (error, NULL);
3384 } else if (mono_llvm_only) {
3385 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3386 if (!is_ok (error))
3387 return NULL;
3388 } else {
3389 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3391 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3393 if (catchExcInMonoError && *exc != NULL) {
3394 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3395 mono_error_set_exception_instance (error, (MonoException*) *exc);
3397 return result;
3400 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3402 MonoException *exc = NULL;
3403 MonoJitInfo *ji;
3404 MonoContext mctx;
3405 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3406 MONO_SIG_HANDLER_GET_CONTEXT;
3408 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3410 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3412 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3413 if (mono_arch_is_int_overflow (ctx, info))
3415 * The spec says this throws ArithmeticException, but MS throws the derived
3416 * OverflowException.
3418 exc = mono_get_exception_overflow ();
3419 else
3420 exc = mono_get_exception_divide_by_zero ();
3421 #else
3422 exc = mono_get_exception_divide_by_zero ();
3423 #endif
3425 if (!ji) {
3426 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3427 goto exit;
3429 mono_sigctx_to_monoctx (ctx, &mctx);
3430 if (mono_dump_start ())
3431 mono_handle_native_crash (mono_get_signame (SIGFPE), &mctx, info);
3432 if (mono_do_crash_chaining) {
3433 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3434 goto exit;
3438 mono_arch_handle_exception (ctx, exc);
3440 exit:
3441 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3444 MONO_SIG_HANDLER_FUNC (, mono_crashing_signal_handler)
3446 MonoContext mctx;
3447 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3448 MONO_SIG_HANDLER_GET_CONTEXT;
3450 if (mono_runtime_get_no_exec ())
3451 exit (1);
3453 mono_sigctx_to_monoctx (ctx, &mctx);
3454 if (mono_dump_start ())
3455 #if defined(HAVE_SIG_INFO) && !defined(HOST_WIN32) // info is a siginfo_t
3456 mono_handle_native_crash (mono_get_signame (info->si_signo), &mctx, info);
3457 #else
3458 mono_handle_native_crash (mono_get_signame (SIGTERM), &mctx, info);
3459 #endif
3460 if (mono_do_crash_chaining) {
3461 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3462 return;
3466 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3468 #define HAVE_SIG_INFO
3469 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3471 #ifdef MONO_SIG_HANDLER_DEBUG
3472 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3473 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3474 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3475 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3476 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3477 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3478 #endif
3480 #endif
3482 gboolean
3483 mono_is_addr_implicit_null_check (void *addr)
3485 /* implicit null checks are only expected to work on the first page. larger
3486 * offsets are expected to have an explicit null check */
3487 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3490 // This function is separate from mono_sigsegv_signal_handler
3491 // so debug_fault_addr can be seen in debugger stacks.
3492 #ifdef MONO_SIG_HANDLER_DEBUG
3493 MONO_NEVER_INLINE
3494 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3495 #else
3496 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3497 #endif
3499 MonoJitInfo *ji = NULL;
3500 MonoDomain *domain = mono_domain_get ();
3501 gpointer fault_addr = NULL;
3502 MonoContext mctx;
3504 #if defined(HAVE_SIG_INFO) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3505 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3506 #endif
3507 #ifdef HAVE_SIG_INFO
3508 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3509 #else
3510 void *info = NULL;
3511 #endif
3512 MONO_SIG_HANDLER_GET_CONTEXT;
3514 mono_sigctx_to_monoctx (ctx, &mctx);
3516 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3517 if (mono_arch_is_single_step_event (info, ctx)) {
3518 mini_get_dbg_callbacks ()->single_step_event (ctx);
3519 return;
3520 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3521 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3522 return;
3524 #endif
3526 #if defined(HAVE_SIG_INFO)
3527 #if !defined(HOST_WIN32)
3528 fault_addr = info->si_addr;
3529 if (mono_aot_is_pagefault (info->si_addr)) {
3530 mono_aot_handle_pagefault (info->si_addr);
3531 return;
3533 int signo = info->si_signo;
3534 #else
3535 int signo = SIGSEGV;
3536 #endif
3538 /* The thread might no be registered with the runtime */
3539 if (!mono_domain_get () || !jit_tls) {
3540 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3541 return;
3542 if (mono_dump_start())
3543 mono_handle_native_crash (mono_get_signame (signo), &mctx, info);
3544 if (mono_do_crash_chaining) {
3545 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3546 return;
3549 #endif
3551 if (domain)
3552 ji = mono_jit_info_table_find_internal (domain, mono_arch_ip_from_context (ctx), TRUE, TRUE);
3554 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3555 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3556 return;
3558 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3559 fault_addr = info->si_addr;
3560 if (fault_addr == NULL) {
3561 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3564 if (jit_tls && jit_tls->stack_size &&
3565 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3567 * The hard-guard page has been hit: there is not much we can do anymore
3568 * Print a hopefully clear message and abort.
3570 mono_handle_hard_stack_ovf (jit_tls, ji, &mctx, (guint8*)info->si_addr);
3571 g_assert_not_reached ();
3572 } else {
3573 /* The original handler might not like that it is executed on an altstack... */
3574 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3575 return;
3577 #ifdef TARGET_AMD64
3578 /* exceptions-amd64.c handles the check itself */
3579 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3580 #else
3581 if (mono_is_addr_implicit_null_check (info->si_addr)) {
3582 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3583 } else {
3584 // FIXME: This shouldn't run on the altstack
3585 if (mono_dump_start ())
3586 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, info);
3588 #endif
3590 #else
3592 if (!ji) {
3593 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3594 return;
3596 if (mono_dump_start ())
3597 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3599 if (mono_do_crash_chaining) {
3600 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3601 return;
3605 if (mono_is_addr_implicit_null_check (fault_addr)) {
3606 mono_arch_handle_exception (ctx, NULL);
3607 } else {
3608 if (mono_dump_start ())
3609 mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3611 #endif
3614 #ifdef MONO_SIG_HANDLER_DEBUG
3616 // This function is separate from mono_sigsegv_signal_handler_debug
3617 // so debug_fault_addr can be seen in debugger stacks.
3618 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3620 #ifdef HOST_WIN32
3621 gpointer const debug_fault_addr = (gpointer)MONO_SIG_HANDLER_GET_INFO () ->ep->ExceptionRecord->ExceptionInformation [1];
3622 #elif defined (HAVE_SIG_INFO)
3623 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3624 #else
3625 #error No extra parameter is passed, not even 0, to avoid any confusion.
3626 #endif
3627 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3630 #endif // MONO_SIG_HANDLER_DEBUG
3632 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3634 MonoException *exc;
3635 MONO_SIG_HANDLER_GET_CONTEXT;
3637 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3639 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3641 mono_arch_handle_exception (ctx, exc);
3643 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3646 #ifndef DISABLE_REMOTING
3647 /* mono_jit_create_remoting_trampoline:
3648 * @method: pointer to the method info
3650 * Creates a trampoline which calls the remoting functions. This
3651 * is used in the vtable of transparent proxies.
3653 * Returns: a pointer to the newly created code
3655 static gpointer
3656 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3658 MonoMethod *nm;
3659 guint8 *addr = NULL;
3661 error_init (error);
3663 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3664 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3665 domain, NULL);
3668 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3669 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3670 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3671 else
3672 nm = method;
3673 return_val_if_nok (error, NULL);
3674 addr = (guint8 *)mono_compile_method_checked (nm, error);
3675 return_val_if_nok (error, NULL);
3676 return mono_get_addr_from_ftnptr (addr);
3678 #endif
3680 static G_GNUC_UNUSED void
3681 no_imt_trampoline (void)
3683 g_assert_not_reached ();
3686 static G_GNUC_UNUSED void
3687 no_vcall_trampoline (void)
3689 g_assert_not_reached ();
3692 static gpointer *vtable_trampolines;
3693 static int vtable_trampolines_size;
3695 gpointer
3696 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3698 int index = slot_index + MONO_IMT_SIZE;
3700 if (mono_llvm_only)
3701 return mini_llvmonly_get_vtable_trampoline (vt, slot_index, index);
3703 g_assert (slot_index >= - MONO_IMT_SIZE);
3704 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3705 mono_jit_lock ();
3706 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3707 int new_size;
3708 gpointer new_table;
3710 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3711 while (new_size <= index)
3712 new_size *= 2;
3713 new_table = g_new0 (gpointer, new_size);
3715 if (vtable_trampolines)
3716 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3717 g_free (vtable_trampolines);
3718 mono_memory_barrier ();
3719 vtable_trampolines = (void **)new_table;
3720 vtable_trampolines_size = new_size;
3722 mono_jit_unlock ();
3725 if (!vtable_trampolines [index])
3726 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3727 return vtable_trampolines [index];
3730 static gpointer
3731 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3733 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3736 static gboolean
3737 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3739 if (mono_llvm_only)
3740 return FALSE;
3742 gpointer *imt = (gpointer*)vt;
3743 imt -= MONO_IMT_SIZE;
3745 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3748 static gpointer
3749 create_delegate_method_ptr (MonoMethod *method, MonoError *error)
3751 gpointer func;
3753 if (method_is_dynamic (method)) {
3754 /* Creating a trampoline would leak memory */
3755 func = mono_compile_method_checked (method, error);
3756 return_val_if_nok (error, NULL);
3757 } else {
3758 gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
3759 return_val_if_nok (error, NULL);
3760 func = mono_create_ftnptr (mono_domain_get (), trampoline);
3762 return func;
3765 static void
3766 mini_init_delegate (MonoDelegateHandle delegate, MonoError *error)
3768 MonoDelegate *del = MONO_HANDLE_RAW (delegate);
3770 if (mono_use_interpreter) {
3771 mini_get_interp_callbacks ()->init_delegate (del, error);
3772 return_if_nok (error);
3775 if (mono_llvm_only) {
3776 g_assert (del->method);
3777 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3778 del->method_ptr = mini_llvmonly_load_method_delegate (del->method, FALSE, FALSE, &del->extra_arg, error);
3779 } else if (!del->method_ptr) {
3780 del->method_ptr = create_delegate_method_ptr (del->method, error);
3781 return_if_nok (error);
3785 char*
3786 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3788 int abs_offset;
3790 abs_offset = offset;
3791 if (abs_offset < 0)
3792 abs_offset = - abs_offset;
3793 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3796 gpointer
3797 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3799 gboolean is_virtual_generic, is_interface, load_imt_reg;
3800 int offset, idx;
3802 static guint8 **cache = NULL;
3803 static int cache_size = 0;
3805 if (!method)
3806 return NULL;
3808 if (MONO_TYPE_ISSTRUCT (sig->ret))
3809 return NULL;
3811 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3812 is_interface = mono_class_is_interface (method->klass);
3813 load_imt_reg = is_virtual_generic || is_interface;
3815 if (is_interface)
3816 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3817 else
3818 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3820 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3821 g_assert (idx >= 0);
3823 /* Resize the cache to idx + 1 */
3824 if (cache_size < idx + 1) {
3825 mono_jit_lock ();
3826 if (cache_size < idx + 1) {
3827 guint8 **new_cache;
3828 int new_cache_size = idx + 1;
3830 new_cache = g_new0 (guint8*, new_cache_size);
3831 if (cache)
3832 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3833 g_free (cache);
3835 mono_memory_barrier ();
3836 cache = new_cache;
3837 cache_size = new_cache_size;
3839 mono_jit_unlock ();
3842 if (cache [idx])
3843 return cache [idx];
3845 /* FIXME Support more cases */
3846 if (mono_ee_features.use_aot_trampolines) {
3847 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3848 g_assert (cache [idx]);
3849 } else {
3850 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3852 return cache [idx];
3856 * mini_parse_debug_option:
3857 * @option: The option to parse.
3859 * Parses debug options for the mono runtime. The options are the same as for
3860 * the MONO_DEBUG environment variable.
3863 gboolean
3864 mini_parse_debug_option (const char *option)
3866 // Empty string is ok as consequence of appending ",foo"
3867 // without first checking for empty.
3868 if (*option == 0)
3869 return TRUE;
3871 if (!strcmp (option, "handle-sigint"))
3872 mini_debug_options.handle_sigint = TRUE;
3873 else if (!strcmp (option, "keep-delegates"))
3874 mini_debug_options.keep_delegates = TRUE;
3875 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3876 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3877 else if (!strcmp (option, "collect-pagefault-stats"))
3878 mini_debug_options.collect_pagefault_stats = TRUE;
3879 else if (!strcmp (option, "break-on-unverified"))
3880 mini_debug_options.break_on_unverified = TRUE;
3881 else if (!strcmp (option, "no-gdb-backtrace"))
3882 mini_debug_options.no_gdb_backtrace = TRUE;
3883 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3884 mini_debug_options.suspend_on_native_crash = TRUE;
3885 else if (!strcmp (option, "suspend-on-exception"))
3886 mini_debug_options.suspend_on_exception = TRUE;
3887 else if (!strcmp (option, "suspend-on-unhandled"))
3888 mini_debug_options.suspend_on_unhandled = TRUE;
3889 else if (!strcmp (option, "dont-free-domains"))
3890 mono_dont_free_domains = TRUE;
3891 else if (!strcmp (option, "dyn-runtime-invoke"))
3892 mini_debug_options.dyn_runtime_invoke = TRUE;
3893 else if (!strcmp (option, "gdb"))
3894 mini_debug_options.gdb = TRUE;
3895 else if (!strcmp (option, "lldb"))
3896 mini_debug_options.lldb = TRUE;
3897 else if (!strcmp (option, "llvm-disable-inlining"))
3898 mini_debug_options.llvm_disable_inlining = TRUE;
3899 else if (!strcmp (option, "llvm-disable-implicit-null-checks"))
3900 mini_debug_options.llvm_disable_implicit_null_checks = TRUE;
3901 else if (!strcmp (option, "explicit-null-checks"))
3902 mini_debug_options.explicit_null_checks = TRUE;
3903 else if (!strcmp (option, "gen-seq-points"))
3904 mini_debug_options.gen_sdb_seq_points = TRUE;
3905 else if (!strcmp (option, "gen-compact-seq-points"))
3906 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3907 else if (!strcmp (option, "no-compact-seq-points"))
3908 mini_debug_options.no_seq_points_compact_data = TRUE;
3909 else if (!strcmp (option, "single-imm-size"))
3910 mini_debug_options.single_imm_size = TRUE;
3911 else if (!strcmp (option, "init-stacks"))
3912 mini_debug_options.init_stacks = TRUE;
3913 else if (!strcmp (option, "casts"))
3914 mini_debug_options.better_cast_details = TRUE;
3915 else if (!strcmp (option, "soft-breakpoints"))
3916 mini_debug_options.soft_breakpoints = TRUE;
3917 else if (!strcmp (option, "check-pinvoke-callconv"))
3918 mini_debug_options.check_pinvoke_callconv = TRUE;
3919 else if (!strcmp (option, "use-fallback-tls"))
3920 mini_debug_options.use_fallback_tls = TRUE;
3921 else if (!strcmp (option, "debug-domain-unload"))
3922 mono_enable_debug_domain_unload (TRUE);
3923 else if (!strcmp (option, "partial-sharing"))
3924 mono_set_partial_sharing_supported (TRUE);
3925 else if (!strcmp (option, "align-small-structs"))
3926 mono_align_small_structs = TRUE;
3927 else if (!strcmp (option, "native-debugger-break"))
3928 mini_debug_options.native_debugger_break = TRUE;
3929 else if (!strcmp (option, "disable_omit_fp"))
3930 mini_debug_options.disable_omit_fp = TRUE;
3931 // This is an internal testing feature.
3932 // Every tail. encountered is required to be optimized.
3933 // It is asserted.
3934 else if (!strcmp (option, "test-tailcall-require"))
3935 mini_debug_options.test_tailcall_require = TRUE;
3936 else if (!strcmp (option, "verbose-gdb"))
3937 mini_debug_options.verbose_gdb = TRUE;
3938 else if (!strcmp (option, "clr-memory-model"))
3939 // FIXME Kill this debug flag
3940 mini_debug_options.weak_memory_model = FALSE;
3941 else if (!strcmp (option, "weak-memory-model"))
3942 mini_debug_options.weak_memory_model = TRUE;
3943 else if (!strcmp (option, "top-runtime-invoke-unhandled"))
3944 mini_debug_options.top_runtime_invoke_unhandled = TRUE;
3945 else if (!strncmp (option, "thread-dump-dir=", 16))
3946 mono_set_thread_dump_dir(g_strdup(option + 16));
3947 else if (!strncmp (option, "aot-skip=", 9)) {
3948 mini_debug_options.aot_skip_set = TRUE;
3949 mini_debug_options.aot_skip = atoi (option + 9);
3950 } else
3951 return FALSE;
3953 return TRUE;
3956 static void
3957 mini_parse_debug_options (void)
3959 char *options = g_getenv ("MONO_DEBUG");
3960 gchar **args, **ptr;
3962 if (!options)
3963 return;
3965 args = g_strsplit (options, ",", -1);
3966 g_free (options);
3968 for (ptr = args; ptr && *ptr; ptr++) {
3969 const char *arg = *ptr;
3971 if (!mini_parse_debug_option (arg)) {
3972 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3973 // test-tailcall-require is also accepted but not documented.
3974 // empty string is also accepted and ignored as a consequence
3975 // of appending ",foo" without checking for empty.
3976 fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break', 'thread-dump-dir=DIR', 'no-verbose-gdb', 'llvm_disable_inlining', 'llvm-disable-self-init', 'llvm-disable-implicit-null-checks', 'weak-memory-model'.\n");
3977 exit (1);
3981 g_strfreev (args);
3984 MonoDebugOptions *
3985 mini_get_debug_options (void)
3987 return &mini_debug_options;
3990 static gpointer
3991 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3993 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3994 gpointer* desc = NULL;
3996 if ((desc = (gpointer*)g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3997 return desc;
3998 #if defined(__mono_ppc64__)
3999 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
4001 desc [0] = addr;
4002 desc [1] = NULL;
4003 desc [2] = NULL;
4004 # endif
4005 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
4006 return desc;
4007 #else
4008 return addr;
4009 #endif
4012 static gpointer
4013 mini_get_addr_from_ftnptr (gpointer descr)
4015 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
4016 return *(gpointer*)descr;
4017 #else
4018 return descr;
4019 #endif
4022 static void
4023 register_jit_stats (void)
4025 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
4026 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
4027 mono_counters_register ("Methods from AOT+LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot_llvm);
4028 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
4029 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
4030 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
4031 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_method_to_ir);
4032 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);
4033 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);
4034 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_long_opts);
4035 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_typechecks);
4036 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop);
4037 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_emulate_ops);
4038 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches);
4039 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs);
4040 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce);
4041 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_alias_analysis);
4042 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_if_conversion);
4043 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_bb_ordering);
4044 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compile_dominator_info);
4045 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compute_natural_loops);
4046 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_insert_safepoints);
4047 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_compute);
4048 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_cprop);
4049 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_deadce);
4050 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_perform_abc_removal);
4051 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_remove);
4052 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop2);
4053 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs2);
4054 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce2);
4055 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches2);
4056 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_vtype_opts);
4057 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);
4058 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);
4059 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_analyze_liveness);
4060 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_linear_scan);
4061 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_arch_allocate_vars);
4062 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_spill_global_vars);
4063 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop3);
4064 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce3);
4065 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_codegen);
4066 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_create_jit_info);
4067 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);
4068 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);
4069 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_time);
4070 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
4071 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
4072 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
4073 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
4074 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
4075 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
4076 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
4077 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
4078 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
4079 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
4080 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
4081 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
4082 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
4083 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
4084 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
4085 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
4086 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
4087 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
4090 static void runtime_invoke_info_free (gpointer value);
4092 static gint
4093 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
4095 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
4096 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
4098 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
4101 static guint
4102 class_method_pair_hash (gconstpointer data)
4104 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
4106 return (gsize)pair->klass ^ (gsize)pair->method;
4109 static void
4110 mini_create_jit_domain_info (MonoDomain *domain)
4112 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
4114 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4115 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4116 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
4117 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4118 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
4119 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
4120 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
4121 info->jump_target_hash = g_hash_table_new (NULL, NULL);
4122 mono_jit_code_hash_init (&info->interp_code_hash);
4124 domain->runtime_info = info;
4127 static void
4128 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
4130 MonoJumpList *jlist = (MonoJumpList *)value;
4131 g_slist_free ((GSList*)jlist->list);
4134 static void
4135 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
4137 GSList *list = (GSList *)value;
4138 g_slist_free (list);
4141 static void
4142 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
4144 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
4145 mono_code_manager_destroy (di->code_mp);
4146 g_free (di);
4149 static void
4150 runtime_invoke_info_free (gpointer value)
4152 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
4154 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4155 if (info->dyn_call_info)
4156 mono_arch_dyn_call_free (info->dyn_call_info);
4157 #endif
4158 g_free (info);
4161 static void
4162 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
4164 g_slist_free ((GSList*)value);
4167 static void
4168 mini_free_jit_domain_info (MonoDomain *domain)
4170 MonoJitDomainInfo *info = domain_jit_info (domain);
4172 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
4173 g_hash_table_destroy (info->jump_target_hash);
4174 if (info->jump_target_got_slot_hash) {
4175 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
4176 g_hash_table_destroy (info->jump_target_got_slot_hash);
4178 if (info->dynamic_code_hash) {
4179 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
4180 g_hash_table_destroy (info->dynamic_code_hash);
4182 g_hash_table_destroy (info->method_code_hash);
4183 g_hash_table_destroy (info->jump_trampoline_hash);
4184 g_hash_table_destroy (info->jit_trampoline_hash);
4185 g_hash_table_destroy (info->delegate_trampoline_hash);
4186 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
4187 g_hash_table_destroy (info->mrgctx_hash);
4188 g_hash_table_destroy (info->method_rgctx_hash);
4189 g_hash_table_destroy (info->interp_method_pointer_hash);
4190 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
4191 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
4192 g_hash_table_destroy (info->seq_points);
4193 g_hash_table_destroy (info->arch_seq_points);
4194 if (info->agent_info)
4195 mini_get_dbg_callbacks ()->free_domain_info (domain);
4196 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
4197 if (info->llvm_jit_callees) {
4198 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
4199 g_hash_table_destroy (info->llvm_jit_callees);
4201 mono_internal_hash_table_destroy (&info->interp_code_hash);
4202 #ifdef ENABLE_LLVM
4203 mono_llvm_free_domain_info (domain);
4204 #endif
4206 g_free (domain->runtime_info);
4207 domain->runtime_info = NULL;
4210 #ifdef ENABLE_LLVM
4211 static gboolean
4212 llvm_init_inner (void)
4214 mono_llvm_init (!mono_compile_aot);
4215 return TRUE;
4217 #endif
4220 * mini_llvm_init:
4222 * Load and initialize LLVM support.
4223 * Return TRUE on success.
4225 gboolean
4226 mini_llvm_init (void)
4228 #ifdef ENABLE_LLVM
4229 static gboolean llvm_inited;
4230 static gboolean init_result;
4232 mono_loader_lock_if_inited ();
4233 if (!llvm_inited) {
4234 init_result = llvm_init_inner ();
4235 llvm_inited = TRUE;
4237 mono_loader_unlock_if_inited ();
4238 return init_result;
4239 #else
4240 return FALSE;
4241 #endif
4244 void
4245 mini_add_profiler_argument (const char *desc)
4247 if (!profile_options)
4248 profile_options = g_ptr_array_new ();
4250 g_ptr_array_add (profile_options, (gpointer) desc);
4254 const MonoEECallbacks *mono_interp_callbacks_pointer;
4256 void
4257 mini_install_interp_callbacks (const MonoEECallbacks *cbs)
4259 mono_interp_callbacks_pointer = cbs;
4262 static MonoDebuggerCallbacks dbg_cbs;
4264 void
4265 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4267 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4268 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4271 MonoDebuggerCallbacks*
4272 mini_get_dbg_callbacks (void)
4274 return &dbg_cbs;
4278 mono_ee_api_version (void)
4280 return MONO_EE_API_VERSION;
4283 void
4284 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4286 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4289 void
4290 mono_interp_to_native_trampoline (gpointer addr, gpointer ccontext)
4292 mini_get_interp_callbacks ()->to_native_trampoline (addr, ccontext);
4295 static gboolean
4296 mini_is_interpreter_enabled (void)
4298 return mono_use_interpreter;
4301 static const char*
4302 mono_get_runtime_build_version (void);
4304 MonoDomain *
4305 mini_init (const char *filename, const char *runtime_version)
4307 ERROR_DECL (error);
4308 MonoDomain *domain;
4310 MonoRuntimeCallbacks callbacks;
4312 static const MonoThreadInfoRuntimeCallbacks ticallbacks = {
4313 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK, mono)
4316 MONO_VES_INIT_BEGIN ();
4318 CHECKED_MONO_INIT ();
4320 #if defined(__linux__)
4321 if (access ("/proc/self/maps", F_OK) != 0) {
4322 g_print ("Mono requires /proc to be mounted.\n");
4323 exit (1);
4325 #endif
4327 mono_interp_stub_init ();
4328 #ifndef DISABLE_INTERPRETER
4329 if (mono_use_interpreter)
4330 mono_ee_interp_init (mono_interp_opts_string);
4331 #endif
4333 mono_debugger_agent_stub_init ();
4334 #ifndef DISABLE_SDB
4335 mono_debugger_agent_init ();
4336 #endif
4338 if (sdb_options)
4339 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4341 mono_os_mutex_init_recursive (&jit_mutex);
4343 mono_cross_helpers_run ();
4345 mono_counters_init ();
4347 mini_jit_init ();
4349 mini_jit_init_job_control ();
4351 /* Happens when using the embedding interface */
4352 if (!default_opt_set)
4353 default_opt = mono_parse_default_optimizations (NULL);
4355 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4356 if (mono_aot_only)
4357 mono_set_generic_sharing_vt_supported (TRUE);
4358 #else
4359 if (mono_llvm_only)
4360 mono_set_generic_sharing_vt_supported (TRUE);
4361 #endif
4363 mono_tls_init_runtime_keys ();
4365 if (!global_codeman)
4366 global_codeman = mono_code_manager_new ();
4368 memset (&callbacks, 0, sizeof (callbacks));
4369 callbacks.create_ftnptr = mini_create_ftnptr;
4370 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4371 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4372 callbacks.get_runtime_build_version = mono_get_runtime_build_version;
4373 callbacks.set_cast_details = mono_set_cast_details;
4374 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4375 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4376 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4377 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4378 callbacks.imt_entry_inited = mini_imt_entry_inited;
4379 callbacks.init_delegate = mini_init_delegate;
4380 #define JIT_INVOKE_WORKS
4381 #ifdef JIT_INVOKE_WORKS
4382 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4383 #endif
4384 #define JIT_TRAMPOLINES_WORK
4385 #ifdef JIT_TRAMPOLINES_WORK
4386 callbacks.compile_method = mono_jit_compile_method;
4387 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4388 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4389 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4390 callbacks.free_method = mono_jit_free_method;
4391 #ifndef DISABLE_REMOTING
4392 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4393 #endif
4394 #endif
4395 #ifndef DISABLE_REMOTING
4396 if (mono_use_interpreter)
4397 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4398 #endif
4399 callbacks.is_interpreter_enabled = mini_is_interpreter_enabled;
4400 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4402 #ifndef DISABLE_CRASH_REPORTING
4403 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4404 #endif
4406 mono_install_callbacks (&callbacks);
4408 #ifndef HOST_WIN32
4409 mono_w32handle_init ();
4410 #endif
4412 mono_thread_info_runtime_init (&ticallbacks);
4414 if (g_hasenv ("MONO_DEBUG")) {
4415 mini_parse_debug_options ();
4418 mono_code_manager_init ();
4420 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4422 static const MonoCodeManagerCallbacks code_manager_callbacks = {
4424 #undef MONO_CODE_MANAGER_CALLBACK
4425 #define MONO_CODE_MANAGER_CALLBACK(ret, name, sig) mono_arch_code_ ## name,
4426 MONO_CODE_MANAGER_CALLBACKS
4430 mono_code_manager_install_callbacks (&code_manager_callbacks);
4431 #endif
4433 mono_hwcap_init ();
4435 mono_arch_cpu_init ();
4437 mono_arch_init ();
4439 mono_unwind_init ();
4441 if (mini_debug_options.lldb || g_hasenv ("MONO_LLDB")) {
4442 mono_lldb_init ("");
4443 mono_dont_free_domains = TRUE;
4446 #ifdef XDEBUG_ENABLED
4447 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4448 if (mono_xdebug) {
4449 mono_xdebug_init (mono_xdebug);
4450 g_free (mono_xdebug);
4451 /* So methods for multiple domains don't have the same address */
4452 mono_dont_free_domains = TRUE;
4453 mono_using_xdebug = TRUE;
4454 } else if (mini_debug_options.gdb) {
4455 mono_xdebug_init ((char*)"gdb");
4456 mono_dont_free_domains = TRUE;
4457 mono_using_xdebug = TRUE;
4459 #endif
4461 #ifdef ENABLE_LLVM
4462 if (mono_use_llvm)
4463 mono_llvm_init (!mono_compile_aot);
4464 #endif
4466 mono_trampolines_init ();
4468 if (default_opt & MONO_OPT_AOT)
4469 mono_aot_init ();
4471 mini_get_dbg_callbacks ()->init ();
4473 #ifdef TARGET_WASM
4474 mono_wasm_debugger_init ();
4475 #endif
4477 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4478 mono_set_generic_sharing_supported (TRUE);
4479 #endif
4481 mono_thread_info_signals_init ();
4483 mono_init_native_crash_info ();
4485 #ifndef MONO_CROSS_COMPILE
4486 mono_runtime_install_handlers ();
4487 #endif
4488 mono_threads_install_cleanup (mini_thread_cleanup);
4490 #ifdef JIT_TRAMPOLINES_WORK
4491 mono_install_create_domain_hook (mini_create_jit_domain_info);
4492 mono_install_free_domain_hook (mini_free_jit_domain_info);
4493 #endif
4494 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4495 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4496 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4498 mono_profiler_state.context_enable = mini_profiler_context_enable;
4499 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4500 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4501 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4502 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4503 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4505 if (profile_options)
4506 for (guint i = 0; i < profile_options->len; i++)
4507 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4509 mono_profiler_started ();
4511 if (mini_debug_options.collect_pagefault_stats)
4512 mono_aot_set_make_unreadable (TRUE);
4514 if (runtime_version)
4515 domain = mono_init_version (filename, runtime_version);
4516 else
4517 domain = mono_init_from_assembly (filename, filename);
4519 if (mono_aot_only) {
4520 /* This helps catch code allocation requests */
4521 mono_code_manager_set_read_only (domain->code_mp);
4522 mono_marshal_use_aot_wrappers (TRUE);
4525 if (mono_llvm_only) {
4526 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline);
4527 mono_set_always_build_imt_trampolines (TRUE);
4528 } else if (mono_aot_only) {
4529 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4530 } else {
4531 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4534 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4535 mono_arch_finish_init ();
4537 /* This must come after mono_init () in the aot-only case */
4538 mono_exceptions_init ();
4540 /* This should come after mono_init () too */
4541 mini_gc_init ();
4543 mono_create_icall_signatures ();
4545 register_jit_stats ();
4547 #define JIT_CALLS_WORK
4548 #ifdef JIT_CALLS_WORK
4549 /* Needs to be called here since register_jit_icall depends on it */
4550 mono_marshal_init ();
4552 mono_arch_register_lowlevel_calls ();
4554 register_icalls ();
4556 mono_generic_sharing_init ();
4557 #endif
4559 #ifdef MONO_ARCH_SIMD_INTRINSICS
4560 mono_simd_intrinsics_init ();
4561 #endif
4563 mono_tasklets_init ();
4565 register_trampolines (domain);
4567 if (mono_compile_aot)
4569 * Avoid running managed code when AOT compiling, since the platform
4570 * might only support aot-only execution.
4572 mono_runtime_set_no_exec (TRUE);
4574 mono_mem_account_register_counters ();
4576 #define JIT_RUNTIME_WORKS
4577 #ifdef JIT_RUNTIME_WORKS
4578 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4579 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4580 mono_error_assert_ok (error);
4581 mono_thread_attach (domain);
4582 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4583 #endif
4584 mono_threads_set_runtime_startup_finished ();
4586 #ifdef ENABLE_EXPERIMENT_TIERED
4587 if (!mono_compile_aot) {
4588 /* create compilation thread in background */
4589 mini_tiered_init ();
4591 #endif
4593 if (mono_profiler_sampling_enabled ())
4594 mono_runtime_setup_stat_profiler ();
4596 MONO_PROFILER_RAISE (runtime_initialized, ());
4598 MONO_VES_INIT_END ();
4600 return domain;
4603 static void
4604 register_icalls (void)
4606 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4607 ves_icall_get_frame_info);
4608 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4609 ves_icall_get_trace);
4610 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4611 mono_runtime_install_handlers);
4612 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4613 mono_runtime_cleanup_handlers);
4615 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4616 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4617 mini_get_dbg_callbacks ()->unhandled_exception);
4618 #endif
4621 * It's important that we pass `TRUE` as the last argument here, as
4622 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4623 * *did* emit a wrapper, we'd be looking at infinite recursion since
4624 * the wrapper would call the icall which would call the wrapper and
4625 * so on.
4627 register_icall (mono_profiler_raise_method_enter, mono_icall_sig_void_ptr_ptr, TRUE);
4628 register_icall (mono_profiler_raise_method_leave, mono_icall_sig_void_ptr_ptr, TRUE);
4629 register_icall (mono_profiler_raise_method_tail_call, mono_icall_sig_void_ptr_ptr, TRUE);
4630 register_icall (mono_profiler_raise_exception_clause, mono_icall_sig_void_ptr_int_int_object, TRUE);
4632 register_icall (mono_trace_enter_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4633 register_icall (mono_trace_leave_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4634 g_assert (mono_get_lmf_addr == mono_tls_get_lmf_addr);
4635 register_icall (mono_jit_set_domain, mono_icall_sig_void_ptr, TRUE);
4636 register_icall (mono_domain_get, mono_icall_sig_ptr, TRUE);
4638 register_icall (mono_llvm_throw_exception, mono_icall_sig_void_object, TRUE);
4639 register_icall (mono_llvm_rethrow_exception, mono_icall_sig_void_object, TRUE);
4640 register_icall (mono_llvm_resume_exception, mono_icall_sig_void, TRUE);
4641 register_icall (mono_llvm_match_exception, mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
4642 register_icall (mono_llvm_clear_exception, NULL, TRUE);
4643 register_icall (mono_llvm_load_exception, mono_icall_sig_object, TRUE);
4644 register_icall (mono_llvm_throw_corlib_exception, mono_icall_sig_void_int, TRUE);
4645 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4646 register_icall (mono_llvm_set_unhandled_exception_handler, NULL, TRUE);
4648 // FIXME: This is broken
4649 #ifndef TARGET_WASM
4650 register_icall (mono_debug_personality, mono_icall_sig_int_int_int_ptr_ptr_ptr, TRUE);
4651 #endif
4652 #endif
4654 if (!mono_llvm_only) {
4655 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception, mono_icall_sig_void_object, TRUE);
4656 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception, mono_icall_sig_void_object, TRUE);
4657 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception, mono_icall_sig_void_ptr, TRUE);
4659 register_icall (mono_thread_get_undeniable_exception, mono_icall_sig_object, FALSE);
4660 register_icall (ves_icall_thread_finish_async_abort, mono_icall_sig_void, FALSE);
4661 register_icall (mono_thread_interruption_checkpoint, mono_icall_sig_object, FALSE);
4662 register_icall (mono_thread_force_interruption_checkpoint_noraise, mono_icall_sig_object, FALSE);
4664 register_icall (mono_threads_state_poll, mono_icall_sig_void, FALSE);
4666 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4667 register_opcode_emulation (OP_LMUL, __emul_lmul, mono_icall_sig_long_long_long, mono_llmult, FALSE);
4668 register_opcode_emulation (OP_LDIV, __emul_ldiv, mono_icall_sig_long_long_long, mono_lldiv, FALSE);
4669 register_opcode_emulation (OP_LDIV_UN, __emul_ldiv_un, mono_icall_sig_long_long_long, mono_lldiv_un, FALSE);
4670 register_opcode_emulation (OP_LREM, __emul_lrem, mono_icall_sig_long_long_long, mono_llrem, FALSE);
4671 register_opcode_emulation (OP_LREM_UN, __emul_lrem_un, mono_icall_sig_long_long_long, mono_llrem_un, FALSE);
4672 #endif
4673 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4674 register_opcode_emulation (OP_LMUL_OVF_UN, __emul_lmul_ovf_un, mono_icall_sig_long_long_long, mono_llmult_ovf_un, FALSE);
4675 register_opcode_emulation (OP_LMUL_OVF, __emul_lmul_ovf, mono_icall_sig_long_long_long, mono_llmult_ovf, FALSE);
4676 #endif
4678 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4679 register_opcode_emulation (OP_LSHL, __emul_lshl, mono_icall_sig_long_long_int32, mono_lshl, TRUE);
4680 register_opcode_emulation (OP_LSHR, __emul_lshr, mono_icall_sig_long_long_int32, mono_lshr, TRUE);
4681 register_opcode_emulation (OP_LSHR_UN, __emul_lshr_un, mono_icall_sig_long_long_int32, mono_lshr_un, TRUE);
4682 #endif
4684 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4685 register_opcode_emulation (OP_IDIV, __emul_op_idiv, mono_icall_sig_int32_int32_int32, mono_idiv, FALSE);
4686 register_opcode_emulation (OP_IDIV_UN, __emul_op_idiv_un, mono_icall_sig_int32_int32_int32, mono_idiv_un, FALSE);
4687 register_opcode_emulation (OP_IREM, __emul_op_irem, mono_icall_sig_int32_int32_int32, mono_irem, FALSE);
4688 register_opcode_emulation (OP_IREM_UN, __emul_op_irem_un, mono_icall_sig_int32_int32_int32, mono_irem_un, FALSE);
4689 #endif
4691 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4692 register_opcode_emulation (OP_IMUL, __emul_op_imul, mono_icall_sig_int32_int32_int32, mono_imul, TRUE);
4693 #endif
4695 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4696 register_opcode_emulation (OP_IMUL_OVF, __emul_op_imul_ovf, mono_icall_sig_int32_int32_int32, mono_imul_ovf, FALSE);
4697 register_opcode_emulation (OP_IMUL_OVF_UN, __emul_op_imul_ovf_un, mono_icall_sig_int32_int32_int32, mono_imul_ovf_un, FALSE);
4698 #endif
4700 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4701 register_opcode_emulation (OP_FDIV, __emul_fdiv, mono_icall_sig_double_double_double, mono_fdiv, FALSE);
4702 #endif
4704 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4705 register_opcode_emulation (OP_FCONV_TO_U8, __emul_fconv_to_u8, mono_icall_sig_ulong_double, mono_fconv_u8_2, FALSE);
4706 register_opcode_emulation (OP_RCONV_TO_U8, __emul_rconv_to_u8, mono_icall_sig_ulong_float, mono_rconv_u8, FALSE);
4707 #endif
4708 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4709 register_opcode_emulation (OP_FCONV_TO_U4, __emul_fconv_to_u4, mono_icall_sig_uint32_double, mono_fconv_u4_2, FALSE);
4710 register_opcode_emulation (OP_RCONV_TO_U4, __emul_rconv_to_u4, mono_icall_sig_uint32_float, mono_rconv_u4, FALSE);
4711 #endif
4712 register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, FALSE);
4713 register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
4714 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);
4715 register_opcode_emulation (OP_RCONV_TO_OVF_I8, __emul_rconv_to_ovf_i8, mono_icall_sig_long_float, mono_rconv_ovf_i8, FALSE);
4716 register_opcode_emulation (OP_RCONV_TO_OVF_U8, __emul_rconv_to_ovf_u8, mono_icall_sig_ulong_float, mono_rconv_ovf_u8, FALSE);
4717 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);
4719 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4720 register_opcode_emulation (OP_FCONV_TO_I8, __emul_fconv_to_i8, mono_icall_sig_long_double, mono_fconv_i8, FALSE);
4721 register_opcode_emulation (OP_RCONV_TO_I8, __emul_rconv_to_i8, mono_icall_sig_long_float, mono_rconv_i8, FALSE);
4722 #endif
4724 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4725 register_opcode_emulation (OP_ICONV_TO_R_UN, __emul_iconv_to_r_un, mono_icall_sig_double_int32, mono_conv_to_r8_un, FALSE);
4726 #endif
4727 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4728 register_opcode_emulation (OP_LCONV_TO_R8, __emul_lconv_to_r8, mono_icall_sig_double_long, mono_lconv_to_r8, FALSE);
4729 #endif
4730 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4731 register_opcode_emulation (OP_LCONV_TO_R4, __emul_lconv_to_r4, mono_icall_sig_float_long, mono_lconv_to_r4, FALSE);
4732 #endif
4733 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4734 register_opcode_emulation (OP_LCONV_TO_R_UN, __emul_lconv_to_r8_un, mono_icall_sig_double_long, mono_lconv_to_r8_un, FALSE);
4735 #endif
4736 #ifdef MONO_ARCH_EMULATE_FREM
4737 register_opcode_emulation (OP_FREM, __emul_frem, mono_icall_sig_double_double_double, mono_fmod, FALSE);
4738 register_opcode_emulation (OP_RREM, __emul_rrem, mono_icall_sig_float_float_float, fmodf, FALSE);
4739 #endif
4741 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4742 if (mono_arch_is_soft_float ()) {
4743 register_opcode_emulation (OP_FSUB, __emul_fsub, mono_icall_sig_double_double_double, mono_fsub, FALSE);
4744 register_opcode_emulation (OP_FADD, __emul_fadd, mono_icall_sig_double_double_double, mono_fadd, FALSE);
4745 register_opcode_emulation (OP_FMUL, __emul_fmul, mono_icall_sig_double_double_double, mono_fmul, FALSE);
4746 register_opcode_emulation (OP_FNEG, __emul_fneg, mono_icall_sig_double_double, mono_fneg, FALSE);
4747 register_opcode_emulation (OP_ICONV_TO_R8, __emul_iconv_to_r8, mono_icall_sig_double_int32, mono_conv_to_r8, FALSE);
4748 register_opcode_emulation (OP_ICONV_TO_R4, __emul_iconv_to_r4, mono_icall_sig_double_int32, mono_conv_to_r4, FALSE);
4749 register_opcode_emulation (OP_FCONV_TO_R4, __emul_fconv_to_r4, mono_icall_sig_double_double, mono_fconv_r4, FALSE);
4750 register_opcode_emulation (OP_FCONV_TO_I1, __emul_fconv_to_i1, mono_icall_sig_int8_double, mono_fconv_i1, FALSE);
4751 register_opcode_emulation (OP_FCONV_TO_I2, __emul_fconv_to_i2, mono_icall_sig_int16_double, mono_fconv_i2, FALSE);
4752 register_opcode_emulation (OP_FCONV_TO_I4, __emul_fconv_to_i4, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4753 register_opcode_emulation (OP_FCONV_TO_U1, __emul_fconv_to_u1, mono_icall_sig_uint8_double, mono_fconv_u1, FALSE);
4754 register_opcode_emulation (OP_FCONV_TO_U2, __emul_fconv_to_u2, mono_icall_sig_uint16_double, mono_fconv_u2, FALSE);
4756 #if TARGET_SIZEOF_VOID_P == 4
4757 register_opcode_emulation (OP_FCONV_TO_I, __emul_fconv_to_i, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4758 #endif
4760 register_opcode_emulation (OP_FBEQ, __emul_fcmp_eq, mono_icall_sig_uint32_double_double, mono_fcmp_eq, FALSE);
4761 register_opcode_emulation (OP_FBLT, __emul_fcmp_lt, mono_icall_sig_uint32_double_double, mono_fcmp_lt, FALSE);
4762 register_opcode_emulation (OP_FBGT, __emul_fcmp_gt, mono_icall_sig_uint32_double_double, mono_fcmp_gt, FALSE);
4763 register_opcode_emulation (OP_FBLE, __emul_fcmp_le, mono_icall_sig_uint32_double_double, mono_fcmp_le, FALSE);
4764 register_opcode_emulation (OP_FBGE, __emul_fcmp_ge, mono_icall_sig_uint32_double_double, mono_fcmp_ge, FALSE);
4765 register_opcode_emulation (OP_FBNE_UN, __emul_fcmp_ne_un, mono_icall_sig_uint32_double_double, mono_fcmp_ne_un, FALSE);
4766 register_opcode_emulation (OP_FBLT_UN, __emul_fcmp_lt_un, mono_icall_sig_uint32_double_double, mono_fcmp_lt_un, FALSE);
4767 register_opcode_emulation (OP_FBGT_UN, __emul_fcmp_gt_un, mono_icall_sig_uint32_double_double, mono_fcmp_gt_un, FALSE);
4768 register_opcode_emulation (OP_FBLE_UN, __emul_fcmp_le_un, mono_icall_sig_uint32_double_double, mono_fcmp_le_un, FALSE);
4769 register_opcode_emulation (OP_FBGE_UN, __emul_fcmp_ge_un, mono_icall_sig_uint32_double_double, mono_fcmp_ge_un, FALSE);
4771 register_opcode_emulation (OP_FCEQ, __emul_fcmp_ceq, mono_icall_sig_uint32_double_double, mono_fceq, FALSE);
4772 register_opcode_emulation (OP_FCGT, __emul_fcmp_cgt, mono_icall_sig_uint32_double_double, mono_fcgt, FALSE);
4773 register_opcode_emulation (OP_FCGT_UN, __emul_fcmp_cgt_un, mono_icall_sig_uint32_double_double, mono_fcgt_un, FALSE);
4774 register_opcode_emulation (OP_FCLT, __emul_fcmp_clt, mono_icall_sig_uint32_double_double, mono_fclt, FALSE);
4775 register_opcode_emulation (OP_FCLT_UN, __emul_fcmp_clt_un, mono_icall_sig_uint32_double_double, mono_fclt_un, FALSE);
4777 register_icall (mono_fload_r4, mono_icall_sig_double_ptr, FALSE);
4778 register_icall (mono_fstore_r4, mono_icall_sig_void_double_ptr, FALSE);
4779 register_icall (mono_fload_r4_arg, mono_icall_sig_uint32_double, FALSE);
4780 register_icall (mono_isfinite_double, mono_icall_sig_int32_double, FALSE);
4782 #endif
4783 register_icall (mono_ckfinite, mono_icall_sig_double_double, FALSE);
4785 #ifdef COMPRESSED_INTERFACE_BITMAP
4786 register_icall (mono_class_interface_match, mono_icall_sig_uint32_ptr_int32, TRUE);
4787 #endif
4789 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4790 #if SIZEOF_REGISTER == 4
4791 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_uint32_double, mono_fconv_u4, TRUE);
4792 #else
4793 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_ulong_double, mono_fconv_u8, TRUE);
4794 #endif
4796 /* other jit icalls */
4797 register_icall (ves_icall_mono_delegate_ctor, mono_icall_sig_void_object_object_ptr, FALSE);
4798 register_icall (ves_icall_mono_delegate_ctor_interp, mono_icall_sig_void_object_object_ptr, FALSE);
4799 register_icall (mono_class_static_field_address,
4800 mono_icall_sig_ptr_ptr_ptr, FALSE);
4801 register_icall (mono_ldtoken_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4802 register_icall (mono_ldtoken_wrapper_generic_shared,
4803 mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4804 register_icall (mono_get_special_static_data, mono_icall_sig_ptr_int, FALSE);
4805 register_icall (ves_icall_mono_ldstr, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4806 register_icall (mono_helper_stelem_ref_check, mono_icall_sig_void_object_object, FALSE);
4807 register_icall (ves_icall_object_new, mono_icall_sig_object_ptr_ptr, FALSE);
4808 register_icall (ves_icall_object_new_specific, mono_icall_sig_object_ptr, FALSE);
4809 register_icall (ves_icall_array_new, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4810 register_icall (ves_icall_array_new_specific, mono_icall_sig_object_ptr_int32, FALSE);
4811 register_icall (ves_icall_runtime_class_init, mono_icall_sig_void_ptr, FALSE);
4812 register_icall (mono_ldftn, mono_icall_sig_ptr_ptr, FALSE);
4813 register_icall (mono_ldvirtfn, mono_icall_sig_ptr_object_ptr, FALSE);
4814 register_icall (mono_ldvirtfn_gshared, mono_icall_sig_ptr_object_ptr, FALSE);
4815 register_icall (mono_helper_compile_generic_method, mono_icall_sig_ptr_object_ptr_ptr, FALSE);
4816 register_icall (mono_helper_ldstr, mono_icall_sig_object_ptr_int, FALSE);
4817 register_icall (mono_helper_ldstr_mscorlib, mono_icall_sig_object_int, FALSE);
4818 register_icall (mono_helper_newobj_mscorlib, mono_icall_sig_object_int, FALSE);
4819 register_icall (mono_value_copy_internal, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
4820 register_icall (mono_object_castclass_unbox, mono_icall_sig_object_object_ptr, FALSE);
4821 register_icall (mono_break, NULL, TRUE);
4822 register_icall (mono_create_corlib_exception_0, mono_icall_sig_object_int, TRUE);
4823 register_icall (mono_create_corlib_exception_1, mono_icall_sig_object_int_object, TRUE);
4824 register_icall (mono_create_corlib_exception_2, mono_icall_sig_object_int_object_object, TRUE);
4825 register_icall (mono_array_new_1, mono_icall_sig_object_ptr_int, FALSE);
4826 register_icall (mono_array_new_2, mono_icall_sig_object_ptr_int_int, FALSE);
4827 register_icall (mono_array_new_3, mono_icall_sig_object_ptr_int_int_int, FALSE);
4828 register_icall (mono_array_new_4, mono_icall_sig_object_ptr_int_int_int_int, FALSE);
4829 register_icall (mono_array_new_n_icall, mono_icall_sig_object_ptr_int_ptr, FALSE);
4830 register_icall (mono_get_native_calli_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4831 register_icall (mono_resume_unwind, mono_icall_sig_void_ptr, TRUE);
4832 register_icall (mono_gsharedvt_constrained_call, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr, FALSE);
4833 register_icall (mono_gsharedvt_value_copy, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4835 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4836 MonoRangeCopyFunction const mono_gc_wbarrier_range_copy = mono_gc_get_range_copy_func ();
4837 register_icall_no_wrapper (mono_gc_wbarrier_range_copy, mono_icall_sig_void_ptr_ptr_int);
4839 register_icall (mono_object_castclass_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4840 register_icall (mono_object_isinst_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4841 register_icall (mono_generic_class_init, mono_icall_sig_void_ptr, FALSE);
4842 register_icall (mono_fill_class_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4843 register_icall (mono_fill_method_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4845 register_dyn_icall (mini_get_dbg_callbacks ()->user_break, mono_debugger_agent_user_break, mono_icall_sig_void, FALSE);
4847 register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_ptr_ptr_ptr, TRUE);
4848 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4849 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4850 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call, mono_icall_sig_ptr_ptr_int_ptr);
4851 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call, mono_icall_sig_ptr_ptr_int_ptr);
4852 /* This needs a wrapper so it can have a preserveall cconv */
4853 register_icall (mini_llvmonly_init_vtable_slot, mono_icall_sig_ptr_ptr_int, FALSE);
4854 register_icall (mini_llvmonly_init_delegate, mono_icall_sig_void_object, TRUE);
4855 register_icall (mini_llvmonly_init_delegate_virtual, mono_icall_sig_void_object_object_ptr, TRUE);
4856 register_icall (mini_llvmonly_throw_nullref_exception, mono_icall_sig_void, TRUE);
4857 register_icall (mini_llvmonly_throw_aot_failed_exception, mono_icall_sig_void_ptr, TRUE);
4859 register_icall (mono_get_assembly_object, mono_icall_sig_object_ptr, TRUE);
4860 register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE);
4861 register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE);
4862 register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE);
4863 register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void);
4865 register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);
4866 register_icall_with_wrapper (mono_monitor_enter_v4_internal, mono_icall_sig_void_obj_ptr);
4867 register_icall_no_wrapper (mono_monitor_enter_fast, mono_icall_sig_int_obj);
4868 register_icall_no_wrapper (mono_monitor_enter_v4_fast, mono_icall_sig_int_obj_ptr);
4870 #ifdef TARGET_IOS
4871 register_icall (pthread_getspecific, mono_icall_sig_ptr_ptr, TRUE);
4872 #endif
4873 /* Register tls icalls */
4874 register_icall_no_wrapper (mono_tls_get_thread_extern, mono_icall_sig_ptr);
4875 register_icall_no_wrapper (mono_tls_get_jit_tls_extern, mono_icall_sig_ptr);
4876 register_icall_no_wrapper (mono_tls_get_domain_extern, mono_icall_sig_ptr);
4877 register_icall_no_wrapper (mono_tls_get_sgen_thread_info_extern, mono_icall_sig_ptr);
4878 register_icall_no_wrapper (mono_tls_get_lmf_addr_extern, mono_icall_sig_ptr);
4880 register_icall_no_wrapper (mono_interp_entry_from_trampoline, mono_icall_sig_void_ptr_ptr);
4881 register_icall_no_wrapper (mono_interp_to_native_trampoline, mono_icall_sig_void_ptr_ptr);
4883 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4884 mono_arch_register_icall ();
4885 #endif
4888 MonoJitStats mono_jit_stats = {0};
4891 * Counters of mono_stats and mono_jit_stats can be read without locking during shutdown.
4892 * For all other contexts, assumes that the domain lock is held.
4893 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4895 MONO_NO_SANITIZE_THREAD
4896 void
4897 mono_runtime_print_stats (void)
4899 if (mono_jit_stats.enabled) {
4900 g_print ("Mono Jit statistics\n");
4901 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4902 mono_jit_stats.max_ratio_method);
4903 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4904 mono_jit_stats.biggest_method);
4906 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4907 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4908 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4909 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4910 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4911 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4912 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4913 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4915 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4916 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4917 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4919 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4920 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4921 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4922 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4924 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4925 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4926 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4927 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4928 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4929 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4930 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4931 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4933 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4934 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4935 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4937 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, NULL);
4938 g_print ("\n");
4942 static void
4943 jit_stats_cleanup (void)
4945 g_free (mono_jit_stats.max_ratio_method);
4946 mono_jit_stats.max_ratio_method = NULL;
4947 g_free (mono_jit_stats.biggest_method);
4948 mono_jit_stats.biggest_method = NULL;
4951 #ifdef DISABLE_CLEANUP
4952 void
4953 mini_cleanup (MonoDomain *domain)
4955 if (mono_stats.enabled)
4956 g_printf ("Printing runtime stats at shutdown\n");
4957 mono_runtime_print_stats ();
4958 jit_stats_cleanup ();
4959 mono_jit_dump_cleanup ();
4961 #else
4962 void
4963 mini_cleanup (MonoDomain *domain)
4965 if (mono_stats.enabled)
4966 g_printf ("Printing runtime stats at shutdown\n");
4967 if (mono_profiler_sampling_enabled ())
4968 mono_runtime_shutdown_stat_profiler ();
4970 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4972 #ifndef DISABLE_COM
4973 mono_cominterop_release_all_rcws ();
4974 #endif
4976 #ifndef MONO_CROSS_COMPILE
4978 * mono_domain_finalize () needs to be called early since it needs the
4979 * execution engine still fully working (it may invoke managed finalizers).
4981 mono_domain_finalize (domain, 2000);
4982 #endif
4984 /* This accesses metadata so needs to be called before runtime shutdown */
4985 mono_runtime_print_stats ();
4986 jit_stats_cleanup ();
4988 #ifndef MONO_CROSS_COMPILE
4989 mono_runtime_cleanup (domain);
4990 #endif
4992 #ifndef ENABLE_NETCORE
4993 mono_threadpool_cleanup ();
4994 #endif
4996 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4998 mono_profiler_cleanup ();
5000 if (profile_options)
5001 g_ptr_array_free (profile_options, TRUE);
5003 mono_icall_cleanup ();
5005 mono_runtime_cleanup_handlers ();
5007 #ifndef MONO_CROSS_COMPILE
5008 mono_domain_free (domain, TRUE);
5009 #endif
5010 free_jit_tls_data (mono_tls_get_jit_tls ());
5012 #ifdef ENABLE_LLVM
5013 if (mono_use_llvm)
5014 mono_llvm_cleanup ();
5015 #endif
5017 mono_aot_cleanup ();
5019 mono_trampolines_cleanup ();
5021 mono_unwind_cleanup ();
5023 mono_code_manager_destroy (global_codeman);
5024 g_free (vtable_trampolines);
5026 mini_jit_cleanup ();
5028 mini_get_interp_callbacks ()->cleanup ();
5030 mono_tramp_info_cleanup ();
5032 mono_arch_cleanup ();
5034 mono_generic_sharing_cleanup ();
5036 mono_cleanup_native_crash_info ();
5038 mono_cleanup ();
5040 mono_trace_cleanup ();
5042 if (mono_inject_async_exc_method)
5043 mono_method_desc_free (mono_inject_async_exc_method);
5045 mono_tls_free_keys ();
5047 mono_os_mutex_destroy (&jit_mutex);
5049 mono_code_manager_cleanup ();
5051 #ifndef HOST_WIN32
5052 mono_w32handle_cleanup ();
5053 #endif
5055 #endif
5057 void
5058 mono_set_defaults (int verbose_level, guint32 opts)
5060 mini_verbose = verbose_level;
5061 mono_set_optimizations (opts);
5064 void
5065 mono_disable_optimizations (guint32 opts)
5067 default_opt &= ~opts;
5070 void
5071 mono_set_optimizations (guint32 opts)
5073 default_opt = opts;
5074 default_opt_set = TRUE;
5075 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
5076 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
5077 #else
5078 if (mono_llvm_only)
5079 mono_set_generic_sharing_vt_supported (TRUE);
5080 #endif
5083 void
5084 mono_set_verbose_level (guint32 level)
5086 mini_verbose = level;
5089 static const char*
5090 mono_get_runtime_build_version (void)
5092 return FULL_VERSION;
5096 * mono_get_runtime_build_info:
5097 * The returned string is owned by the caller. The returned string
5098 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
5099 * \returns the runtime version + build date in string format.
5101 char*
5102 mono_get_runtime_build_info (void)
5104 if (mono_build_date)
5105 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
5106 else
5107 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
5110 static void
5111 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
5113 GHashTable *assemblies = (GHashTable*)user_data;
5114 MonoImage *image = mono_assembly_get_image_internal (ass);
5115 MonoMethod *method, *invoke;
5116 int i, count = 0;
5118 if (g_hash_table_lookup (assemblies, ass))
5119 return;
5121 g_hash_table_insert (assemblies, ass, ass);
5123 if (mini_verbose > 0)
5124 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
5126 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5127 ERROR_DECL (error);
5129 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
5130 if (!method) {
5131 mono_error_cleanup (error); /* FIXME don't swallow the error */
5132 continue;
5134 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
5135 continue;
5136 if (method->is_generic || mono_class_is_gtd (method->klass))
5137 continue;
5139 count++;
5140 if (mini_verbose > 1) {
5141 char * desc = mono_method_full_name (method, TRUE);
5142 g_print ("Compiling %d %s\n", count, desc);
5143 g_free (desc);
5145 mono_compile_method_checked (method, error);
5146 if (!is_ok (error)) {
5147 mono_error_cleanup (error); /* FIXME don't swallow the error */
5148 continue;
5150 if (strcmp (method->name, "Finalize") == 0) {
5151 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
5152 mono_compile_method_checked (invoke, error);
5153 mono_error_assert_ok (error);
5155 #ifndef DISABLE_REMOTING
5156 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
5157 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
5158 mono_error_assert_ok (error);
5159 mono_compile_method_checked (invoke, error);
5160 mono_error_assert_ok (error);
5162 #endif
5165 /* Load and precompile referenced assemblies as well */
5166 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
5167 mono_assembly_load_reference (image, i);
5168 if (image->references [i])
5169 mono_precompile_assembly (image->references [i], assemblies);
5173 void mono_precompile_assemblies ()
5175 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
5177 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
5179 g_hash_table_destroy (assemblies);
5183 * Used by LLVM.
5184 * Have to export this for AOT.
5186 void
5187 mono_personality (void)
5189 /* Not used */
5190 g_assert_not_reached ();
5193 static MonoBreakPolicy
5194 always_insert_breakpoint (MonoMethod *method)
5196 return MONO_BREAK_POLICY_ALWAYS;
5199 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5202 * mono_set_break_policy:
5203 * \param policy_callback the new callback function
5205 * Allow embedders to decide whether to actually obey breakpoint instructions
5206 * (both break IL instructions and \c Debugger.Break method calls), for example
5207 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5208 * untrusted or semi-trusted code.
5210 * \p policy_callback will be called every time a break point instruction needs to
5211 * be inserted with the method argument being the method that calls \c Debugger.Break
5212 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5213 * if it wants the breakpoint to not be effective in the given method.
5214 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5216 void
5217 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5219 if (policy_callback)
5220 break_policy_func = policy_callback;
5221 else
5222 break_policy_func = always_insert_breakpoint;
5225 gboolean
5226 mini_should_insert_breakpoint (MonoMethod *method)
5228 switch (break_policy_func (method)) {
5229 case MONO_BREAK_POLICY_ALWAYS:
5230 return TRUE;
5231 case MONO_BREAK_POLICY_NEVER:
5232 return FALSE;
5233 case MONO_BREAK_POLICY_ON_DBG:
5234 g_warning ("mdb no longer supported");
5235 return FALSE;
5236 default:
5237 g_warning ("Incorrect value returned from break policy callback");
5238 return FALSE;
5242 // Custom handlers currently only implemented by Windows.
5243 #ifndef HOST_WIN32
5244 gboolean
5245 mono_runtime_install_custom_handlers (const char *handlers)
5247 return FALSE;
5250 void
5251 mono_runtime_install_custom_handlers_usage (void)
5253 fprintf (stdout,
5254 "Custom Handlers:\n"
5255 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5256 " separated list of available handlers to install.\n"
5257 "\n"
5258 "No handlers supported on current platform.\n");
5260 #endif /* HOST_WIN32 */