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