[coop] Transition various public APIs into an external/internal form to avoid unneces...
[mono-project.git] / mono / mini / mini-runtime.c
blob2a88fcfe361afb700cf3a3026d91154871157240
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 #ifdef HAVE_SIGNAL_H
27 #include <signal.h>
28 #endif
30 #include <mono/utils/memcheck.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/assembly-internals.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/tokentype.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/metadata/threads.h>
41 #include <mono/metadata/appdomain.h>
42 #include <mono/metadata/debug-helpers.h>
43 #include <mono/metadata/domain-internals.h>
44 #include <mono/metadata/profiler-private.h>
45 #include <mono/metadata/mono-config.h>
46 #include <mono/metadata/environment.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/threads-types.h>
50 #include <mono/metadata/mempool-internals.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/runtime.h>
53 #include <mono/metadata/reflection-internals.h>
54 #include <mono/metadata/monitor.h>
55 #include <mono/metadata/icall-internals.h>
56 #include <mono/metadata/loader-internals.h>
57 #define MONO_MATH_DECLARE_ALL 1
58 #include <mono/utils/mono-math.h>
59 #include <mono/utils/mono-compiler.h>
60 #include <mono/utils/mono-counters.h>
61 #include <mono/utils/mono-error-internals.h>
62 #include <mono/utils/mono-logger-internals.h>
63 #include <mono/utils/mono-mmap.h>
64 #include <mono/utils/mono-path.h>
65 #include <mono/utils/mono-tls.h>
66 #include <mono/utils/mono-hwcap.h>
67 #include <mono/utils/dtrace.h>
68 #include <mono/utils/mono-signal-handler.h>
69 #include <mono/utils/mono-threads.h>
70 #include <mono/utils/mono-threads-coop.h>
71 #include <mono/utils/checked-build.h>
72 #include <mono/utils/mono-compiler.h>
73 #include <mono/utils/mono-proclib.h>
74 #include <mono/metadata/w32handle.h>
75 #include <mono/metadata/threadpool.h>
77 #include "mini.h"
78 #include "seq-points.h"
79 #include "tasklets.h"
80 #include <string.h>
81 #include <ctype.h>
82 #include "trace.h"
83 #include "version.h"
84 #include "aot-compiler.h"
85 #include "aot-runtime.h"
86 #include "llvmonly-runtime.h"
88 #include "jit-icalls.h"
90 #include "mini-gc.h"
91 #include "mini-llvm.h"
92 #include "debugger-agent.h"
93 #include "lldb.h"
94 #include "mini-runtime.h"
95 #include "interp/interp.h"
97 #ifdef MONO_ARCH_LLVM_SUPPORTED
98 #ifdef ENABLE_LLVM
99 #include "mini-llvm-cpp.h"
100 #include "llvm-jit.h"
101 #endif
102 #endif
103 #include "mono/metadata/icall-signatures.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_interpreter = FALSE;
129 const char *mono_interp_opts_string = NULL;
131 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
132 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
133 static mono_mutex_t jit_mutex;
135 static MonoCodeManager *global_codeman;
137 MonoDebugOptions mini_debug_options;
138 char *sdb_options;
140 #ifdef VALGRIND_JIT_REGISTER_MAP
141 int valgrind_register;
142 #endif
143 GList* mono_aot_paths;
145 static GPtrArray *profile_options;
147 static GSList *tramp_infos;
148 GSList *mono_interp_only_classes;
150 static void register_icalls (void);
152 gboolean
153 mono_running_on_valgrind (void)
155 #ifndef HOST_WIN32
156 if (RUNNING_ON_VALGRIND){
157 #ifdef VALGRIND_JIT_REGISTER_MAP
158 valgrind_register = TRUE;
159 #endif
160 return TRUE;
161 } else
162 #endif
163 return FALSE;
166 typedef struct {
167 void *ip;
168 MonoMethod *method;
169 } FindTrampUserData;
171 static void
172 find_tramp (gpointer key, gpointer value, gpointer user_data)
174 FindTrampUserData *ud = (FindTrampUserData*)user_data;
176 if (value == ud->ip)
177 ud->method = (MonoMethod*)key;
180 /* debug function */
181 char*
182 mono_get_method_from_ip (void *ip)
184 MonoJitInfo *ji;
185 MonoMethod *method;
186 char *method_name;
187 char *res;
188 MonoDomain *domain = mono_domain_get ();
189 MonoDebugSourceLocation *location;
190 FindTrampUserData user_data;
192 if (!domain)
193 domain = mono_get_root_domain ();
195 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
196 if (!ji) {
197 user_data.ip = ip;
198 user_data.method = NULL;
199 mono_domain_lock (domain);
200 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
201 mono_domain_unlock (domain);
202 if (user_data.method) {
203 char *mname = mono_method_full_name (user_data.method, TRUE);
204 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
205 g_free (mname);
206 return res;
208 else
209 return NULL;
210 } else if (ji->is_trampoline) {
211 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
212 return res;
215 method = jinfo_get_method (ji);
216 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
217 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
219 char *file_loc = NULL;
220 if (location)
221 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
223 res = g_strdup_printf (" %s [{%p} + 0x%x] %s (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), file_loc ? file_loc : "", ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
225 mono_debug_free_source_location (location);
226 g_free (method_name);
227 g_free (file_loc);
229 return res;
233 * mono_pmip:
234 * \param ip an instruction pointer address
236 * This method is used from a debugger to get the name of the
237 * method at address \p ip. This routine is typically invoked from
238 * a debugger like this:
240 * (gdb) print mono_pmip ($pc)
242 * \returns the name of the method at address \p ip.
244 G_GNUC_UNUSED char *
245 mono_pmip (void *ip)
247 return mono_get_method_from_ip (ip);
251 * mono_print_method_from_ip:
252 * \param ip an instruction pointer address
254 * This method is used from a debugger to get the name of the
255 * method at address \p ip.
257 * This prints the name of the method at address \p ip in the standard
258 * output. Unlike \c mono_pmip which returns a string, this routine
259 * prints the value on the standard output.
261 MONO_ATTR_USED void
262 mono_print_method_from_ip (void *ip)
264 MonoJitInfo *ji;
265 char *method;
266 MonoDebugSourceLocation *source;
267 MonoDomain *domain = mono_domain_get ();
268 MonoDomain *target_domain = mono_domain_get ();
269 FindTrampUserData user_data;
270 MonoGenericSharingContext*gsctx;
271 const char *shared_type;
273 if (!domain)
274 domain = mono_get_root_domain ();
275 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
276 if (ji && ji->is_trampoline) {
277 MonoTrampInfo *tinfo = ji->d.tramp_info;
279 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
280 return;
283 if (!ji) {
284 user_data.ip = ip;
285 user_data.method = NULL;
286 mono_domain_lock (domain);
287 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
288 mono_domain_unlock (domain);
290 if (user_data.method) {
291 char *mname = mono_method_full_name (user_data.method, TRUE);
292 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
293 g_free (mname);
294 return;
297 g_print ("No method at %p\n", ip);
298 fflush (stdout);
299 return;
301 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
302 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
304 gsctx = mono_jit_info_get_generic_sharing_context (ji);
305 shared_type = "";
306 if (gsctx) {
307 if (gsctx->is_gsharedvt)
308 shared_type = "gsharedvt ";
309 else
310 shared_type = "gshared ";
313 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);
315 if (source)
316 g_print ("%s:%d\n", source->source_file, source->row);
317 fflush (stdout);
319 mono_debug_free_source_location (source);
320 g_free (method);
324 * mono_method_same_domain:
326 * Determine whenever two compiled methods are in the same domain, thus
327 * the address of the callee can be embedded in the caller.
329 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
331 MonoMethod *cmethod;
333 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
334 return FALSE;
337 * If the call was made from domain-neutral to domain-specific
338 * code, we can't patch the call site.
340 if (caller->domain_neutral && !callee->domain_neutral)
341 return FALSE;
343 cmethod = jinfo_get_method (caller);
344 if ((cmethod->klass == mono_defaults.appdomain_class) &&
345 (strstr (cmethod->name, "InvokeInDomain"))) {
346 /* The InvokeInDomain methods change the current appdomain */
347 return FALSE;
350 return TRUE;
354 * mono_global_codeman_reserve:
356 * Allocate code memory from the global code manager.
358 void *(mono_global_codeman_reserve) (int size)
360 void *ptr;
362 if (mono_aot_only)
363 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
365 if (!global_codeman) {
366 /* This can happen during startup */
367 global_codeman = mono_code_manager_new ();
368 return mono_code_manager_reserve (global_codeman, size);
370 else {
371 mono_jit_lock ();
372 ptr = mono_code_manager_reserve (global_codeman, size);
373 mono_jit_unlock ();
374 return ptr;
378 /* The callback shouldn't take any locks */
379 void
380 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
382 mono_jit_lock ();
383 mono_code_manager_foreach (global_codeman, func, user_data);
384 mono_jit_unlock ();
388 * mono_create_unwind_op:
390 * Create an unwind op with the given parameters.
392 MonoUnwindOp*
393 mono_create_unwind_op (int when, int tag, int reg, int val)
395 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
397 op->op = tag;
398 op->reg = reg;
399 op->val = val;
400 op->when = when;
402 return op;
405 MonoJumpInfoToken *
406 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
408 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
409 res->image = image;
410 res->token = token;
411 res->has_context = context != NULL;
412 if (context)
413 memcpy (&res->context, context, sizeof (MonoGenericContext));
415 return res;
418 MonoJumpInfoToken *
419 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
421 return mono_jump_info_token_new2 (mp, image, token, NULL);
425 * mono_tramp_info_create:
427 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
428 * of JI, and UNWIND_OPS.
430 MonoTrampInfo*
431 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
433 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
435 info->name = g_strdup (name);
436 info->code = code;
437 info->code_size = code_size;
438 info->ji = ji;
439 info->unwind_ops = unwind_ops;
441 return info;
444 void
445 mono_tramp_info_free (MonoTrampInfo *info)
447 g_free (info->name);
449 // FIXME: ji
450 mono_free_unwind_info (info->unwind_ops);
451 if (info->owns_uw_info)
452 g_free (info->uw_info);
453 g_free (info);
456 static void
457 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
459 MonoJitInfo *ji;
461 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
462 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
463 ji->d.tramp_info = info;
464 ji->is_trampoline = TRUE;
466 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
468 mono_jit_info_table_add (domain, ji);
472 * mono_tramp_info_register:
474 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
475 * INFO can be NULL.
476 * Frees INFO.
478 static void
479 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
481 MonoTrampInfo *copy;
483 if (!info)
484 return;
486 if (!domain)
487 domain = mono_get_root_domain ();
489 if (domain)
490 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
491 else
492 copy = g_new0 (MonoTrampInfo, 1);
494 copy->code = info->code;
495 copy->code_size = info->code_size;
496 copy->name = g_strdup (info->name);
498 if (info->unwind_ops) {
499 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
500 copy->owns_uw_info = TRUE;
501 if (domain) {
502 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
503 guint8 *temp = copy->uw_info;
504 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
505 memcpy (copy->uw_info, temp, copy->uw_info_len);
506 g_free (temp);
508 } else {
509 /* Trampolines from aot have the unwind ops already encoded */
510 copy->uw_info = info->uw_info;
511 copy->uw_info_len = info->uw_info_len;
514 mono_save_trampoline_xdebug_info (info);
515 mono_lldb_save_trampoline_info (info);
517 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
518 if (!aot)
519 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
520 #endif
522 if (!domain) {
523 /* If no root domain has been created yet, postpone the registration. */
524 mono_jit_lock ();
525 tramp_infos = g_slist_prepend (tramp_infos, copy);
526 mono_jit_unlock ();
527 } else if (copy->uw_info) {
528 /* Only register trampolines that have unwind infos */
529 register_trampoline_jit_info (domain, copy);
532 if (mono_jit_map_is_enabled ())
533 mono_emit_jit_tramp (info->code, info->code_size, info->name);
535 mono_tramp_info_free (info);
538 void
539 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
541 mono_tramp_info_register_internal (info, domain, FALSE);
544 void
545 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
547 mono_tramp_info_register_internal (info, domain, TRUE);
550 static void
551 mono_tramp_info_cleanup (void)
553 GSList *l;
555 for (l = tramp_infos; l; l = l->next) {
556 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
558 mono_tramp_info_free (info);
560 g_slist_free (tramp_infos);
563 /* Register trampolines created before the root domain was created in the jit info tables */
564 static void
565 register_trampolines (MonoDomain *domain)
567 GSList *l;
569 for (l = tramp_infos; l; l = l->next) {
570 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
572 register_trampoline_jit_info (domain, info);
576 G_GNUC_UNUSED static void
577 break_count (void)
582 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
583 * Set a breakpoint in break_count () to break the last time <x> is done.
585 G_GNUC_UNUSED gboolean
586 mono_debug_count (void)
588 static int count = 0, int_val = 0;
589 static gboolean inited, has_value = FALSE;
591 count ++;
593 if (!inited) {
594 char *value = g_getenv ("COUNT");
595 if (value) {
596 int_val = atoi (value);
597 g_free (value);
598 has_value = TRUE;
600 inited = TRUE;
603 if (!has_value)
604 return TRUE;
606 if (count == int_val)
607 break_count ();
609 if (count > int_val)
610 return FALSE;
612 return TRUE;
615 MonoMethod*
616 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
618 gboolean check_exc = TRUE;
620 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
621 /* This icall is used to check for exceptions, so don't check in the wrapper */
622 check_exc = FALSE;
624 return mono_marshal_get_icall_wrapper (callinfo, check_exc);
627 gconstpointer
628 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
630 ERROR_DECL (error);
631 MonoMethod *wrapper;
632 gconstpointer addr, trampoline;
633 MonoDomain *domain = mono_get_root_domain ();
635 if (callinfo->wrapper)
636 return callinfo->wrapper;
638 wrapper = mono_icall_get_wrapper_method (callinfo);
640 if (do_compile) {
641 addr = mono_compile_method_checked (wrapper, error);
642 mono_error_assert_ok (error);
643 mono_memory_barrier ();
644 callinfo->wrapper = addr;
645 return addr;
646 } else {
647 if (callinfo->trampoline)
648 return callinfo->trampoline;
649 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
650 mono_error_assert_ok (error);
651 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
653 mono_loader_lock ();
654 if (!callinfo->trampoline) {
655 mono_register_jit_icall_wrapper (callinfo, trampoline);
656 callinfo->trampoline = trampoline;
658 mono_loader_unlock ();
660 return callinfo->trampoline;
664 gconstpointer
665 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
667 return mono_icall_get_wrapper_full (callinfo, FALSE);
670 static MonoJitDynamicMethodInfo*
671 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
673 MonoJitDynamicMethodInfo *res;
675 if (domain_jit_info (domain)->dynamic_code_hash)
676 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
677 else
678 res = NULL;
679 return res;
682 #ifdef __cplusplus
683 template <typename T>
684 static void
685 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, T func, const char *symbol, gboolean no_wrapper)
686 #else
687 static void
688 register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, const char *name, MonoMethodSignature *sig, gpointer func, const char *symbol, gboolean no_wrapper)
689 #endif
691 #ifndef DISABLE_JIT
692 mini_register_opcode_emulation (opcode, jit_icall_info, name, sig, func, symbol, no_wrapper);
693 #else
694 // FIXME ifdef in mini_register_opcode_emulation and just call it.
696 g_assert (!sig->hasthis);
697 g_assert (sig->param_count < 3);
699 mono_register_jit_icall_info (jit_icall_info, func, name, sig, no_wrapper, symbol);
700 #endif
703 #define register_opcode_emulation(opcode, name, sig, func, no_wrapper) \
704 (register_opcode_emulation ((opcode), &mono_get_jit_icall_info ()->name, #name, (sig), func, #func, (no_wrapper)))
707 * For JIT icalls implemented in C.
708 * NAME should be the same as the name of the C function whose address is FUNC.
709 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
710 * can't throw exceptions.
712 * func is an identifier, that names a function, and is also in jit-icall-reg.h,
713 * and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
715 * The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
716 * nor does the C++ overload fmod (mono_fmod instead). These functions therefore
717 * must be extern "C".
719 #define register_icall(func, sig, avoid_wrapper) \
720 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (avoid_wrapper), #func))
722 #define register_icall_no_wrapper(func, sig) register_icall (func, sig, TRUE)
723 #define register_icall_with_wrapper(func, sig) register_icall (func, sig, FALSE)
726 * Register an icall where FUNC is dynamically generated or otherwise not
727 * possible to link to it using NAME during AOT.
729 * func is an expression, such a local variable or a function call to get a function pointer.
730 * name is an identifier
732 * Providing func and name separately is what distinguishes "dyn" from regular.
734 * This also passes last parameter c_symbol=NULL since there is not a directly linkable symbol.
736 #define register_dyn_icall(func, name, sig, save) \
737 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->name, (func), #name, (sig), (save), NULL))
739 MonoLMF *
740 mono_get_lmf (void)
742 MonoJitTlsData *jit_tls;
744 if ((jit_tls = mono_tls_get_jit_tls ()))
745 return jit_tls->lmf;
747 * We do not assert here because this function can be called from
748 * mini-gc.c on a thread that has not executed any managed code, yet
749 * (the thread object allocation can trigger a collection).
751 return NULL;
754 void
755 mono_set_lmf (MonoLMF *lmf)
757 (*mono_get_lmf_addr ()) = lmf;
760 static void
761 mono_set_jit_tls (MonoJitTlsData *jit_tls)
763 MonoThreadInfo *info;
765 mono_tls_set_jit_tls (jit_tls);
767 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
768 info = mono_thread_info_current ();
769 if (info)
770 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
773 static void
774 mono_set_lmf_addr (MonoLMF **lmf_addr)
776 MonoThreadInfo *info;
778 mono_tls_set_lmf_addr (lmf_addr);
780 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
781 info = mono_thread_info_current ();
782 if (info)
783 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
787 * mono_push_lmf:
789 * Push an MonoLMFExt frame on the LMF stack.
791 void
792 mono_push_lmf (MonoLMFExt *ext)
794 MonoLMF **lmf_addr;
796 lmf_addr = mono_get_lmf_addr ();
798 ext->lmf.previous_lmf = *lmf_addr;
799 /* Mark that this is a MonoLMFExt */
800 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
802 mono_set_lmf ((MonoLMF*)ext);
806 * mono_pop_lmf:
808 * Pop the last frame from the LMF stack.
810 void
811 mono_pop_lmf (MonoLMF *lmf)
813 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
817 * mono_jit_thread_attach:
819 * Called by Xamarin.Mac and other products. Attach thread to runtime if
820 * needed and switch to @domain.
822 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
824 * If the thread is newly-attached, put into GC Safe mode.
826 * @return the original domain which needs to be restored, or NULL.
828 MonoDomain*
829 mono_jit_thread_attach (MonoDomain *domain)
831 MonoDomain *orig;
832 gboolean attached;
834 if (!domain) {
835 /* Happens when called from AOTed code which is only used in the root domain. */
836 domain = mono_get_root_domain ();
839 g_assert (domain);
841 attached = mono_tls_get_jit_tls () != NULL;
843 if (!attached) {
844 mono_thread_attach (domain);
846 // #678164
847 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
849 /* mono_jit_thread_attach is external-only and not called by
850 * the runtime on any of our own threads. So if we get here,
851 * the thread is running native code - leave it in GC Safe mode
852 * and leave it to the n2m invoke wrappers or MONO_API entry
853 * points to switch to GC Unsafe.
855 MONO_STACKDATA (stackdata);
856 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
859 orig = mono_domain_get ();
860 if (orig != domain)
861 mono_domain_set_fast (domain, TRUE);
863 return orig != domain ? orig : NULL;
867 * mono_jit_set_domain:
869 * Set domain to @domain if @domain is not null
871 void
872 mono_jit_set_domain (MonoDomain *domain)
874 g_assert (!mono_threads_is_blocking_transition_enabled ());
876 if (domain)
877 mono_domain_set_fast (domain, TRUE);
881 * mono_thread_abort:
882 * \param obj exception object
883 * Abort the thread, print exception information and stack trace
885 static void
886 mono_thread_abort (MonoObject *obj)
888 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
890 /* handle_remove should be eventually called for this thread, too
891 g_free (jit_tls);*/
893 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
894 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
895 ((obj->vtable->klass) == mono_class_try_get_appdomain_unloaded_exception_class () &&
896 mono_thread_info_current ()->runtime_thread)) {
897 mono_thread_exit ();
898 } else {
899 mono_invoke_unhandled_exception_hook (obj);
903 static MonoJitTlsData*
904 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
906 MonoJitTlsData *jit_tls;
907 MonoLMF *lmf;
909 jit_tls = mono_tls_get_jit_tls ();
910 if (jit_tls)
911 return jit_tls;
913 jit_tls = g_new0 (MonoJitTlsData, 1);
915 jit_tls->abort_func = abort_func;
916 jit_tls->end_of_stack = stack_start;
918 mono_set_jit_tls (jit_tls);
920 lmf = g_new0 (MonoLMF, 1);
921 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
923 jit_tls->first_lmf = lmf;
925 mono_set_lmf_addr (&jit_tls->lmf);
927 jit_tls->lmf = lmf;
929 #ifdef MONO_ARCH_HAVE_TLS_INIT
930 mono_arch_tls_init ();
931 #endif
933 mono_setup_altstack (jit_tls);
935 return jit_tls;
938 static void
939 free_jit_tls_data (MonoJitTlsData *jit_tls)
941 //This happens during AOT cuz the thread is never attached
942 if (!jit_tls)
943 return;
944 mono_arch_free_jit_tls_data (jit_tls);
945 mono_free_altstack (jit_tls);
947 g_free (jit_tls->first_lmf);
948 g_free (jit_tls->interp_context);
949 g_free (jit_tls);
952 static void
953 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
955 MonoThreadInfo *thread;
956 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
957 thread = mono_thread_info_current_unchecked ();
958 if (thread)
959 thread->jit_data = jit_tls;
961 mono_arch_cpu_init ();
964 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
966 static void
967 mono_thread_abort_dummy (MonoObject *obj)
969 if (mono_thread_attach_aborted_cb)
970 mono_thread_attach_aborted_cb (obj);
971 else
972 mono_thread_abort (obj);
975 static void
976 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
978 MonoThreadInfo *thread;
979 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
980 thread = mono_thread_info_current_unchecked ();
981 if (thread)
982 thread->jit_data = jit_tls;
984 mono_arch_cpu_init ();
987 static void
988 mini_thread_cleanup (MonoNativeThreadId tid)
990 MonoJitTlsData *jit_tls = NULL;
991 MonoThreadInfo *info;
993 info = mono_thread_info_current_unchecked ();
995 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
996 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
997 * not a trivial thing.
999 * The current offender is mono_thread_manage which cleanup threads from the outside.
1001 if (info && mono_thread_info_get_tid (info) == tid) {
1002 jit_tls = info->jit_data;
1003 info->jit_data = NULL;
1005 mono_set_jit_tls (NULL);
1007 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1008 if (mono_get_lmf ()) {
1009 mono_set_lmf (NULL);
1010 mono_set_lmf_addr (NULL);
1012 } else {
1013 info = mono_thread_info_lookup (tid);
1014 if (info) {
1015 jit_tls = info->jit_data;
1016 info->jit_data = NULL;
1018 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1021 if (jit_tls)
1022 free_jit_tls_data (jit_tls);
1025 MonoJumpInfo *
1026 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1028 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1030 ji->ip.i = ip;
1031 ji->type = type;
1032 ji->data.target = target;
1033 ji->next = list;
1035 return ji;
1038 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1040 static const char* const patch_info_str[] = {
1041 #define PATCH_INFO(a,b) "" #a,
1042 #include "patch-info.h"
1043 #undef PATCH_INFO
1046 const char*
1047 mono_ji_type_to_string (MonoJumpInfoType type)
1049 return patch_info_str [type];
1052 void
1053 mono_print_ji (const MonoJumpInfo *ji)
1055 const char *type = patch_info_str [ji->type];
1056 switch (ji->type) {
1057 case MONO_PATCH_INFO_RGCTX_FETCH:
1058 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1059 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1061 printf ("[%s ", type);
1062 mono_print_ji (entry->data);
1063 printf (" -> %s]", mono_rgctx_info_type_to_str (entry->info_type));
1064 break;
1066 case MONO_PATCH_INFO_METHOD:
1067 case MONO_PATCH_INFO_METHODCONST:
1068 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1069 char *s = mono_method_get_full_name (ji->data.method);
1070 printf ("[%s %s]", type, s);
1071 g_free (s);
1072 break;
1074 case MONO_PATCH_INFO_JIT_ICALL_ID:
1075 printf ("[JIT_ICALL %s]", mono_find_jit_icall_info (ji->data.jit_icall_id)->name);
1076 break;
1077 case MONO_PATCH_INFO_CLASS:
1078 case MONO_PATCH_INFO_VTABLE: {
1079 char *name = mono_class_full_name (ji->data.klass);
1080 printf ("[%s %s]", type, name);
1081 g_free (name);
1082 break;
1084 default:
1085 printf ("[%s]", type);
1086 break;
1090 #else
1092 const char*
1093 mono_ji_type_to_string (MonoJumpInfoType type)
1095 return "";
1098 void
1099 mono_print_ji (const MonoJumpInfo *ji)
1103 #endif
1106 * mono_patch_info_dup_mp:
1108 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1110 MonoJumpInfo*
1111 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1113 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1114 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1116 switch (patch_info->type) {
1117 case MONO_PATCH_INFO_RVA:
1118 case MONO_PATCH_INFO_LDSTR:
1119 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1120 case MONO_PATCH_INFO_LDTOKEN:
1121 case MONO_PATCH_INFO_DECLSEC:
1122 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1123 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1124 break;
1125 case MONO_PATCH_INFO_SWITCH:
1126 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1127 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1128 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1129 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1130 break;
1131 case MONO_PATCH_INFO_RGCTX_FETCH:
1132 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1133 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1134 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1135 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1136 break;
1137 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1138 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1139 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1140 break;
1141 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1142 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1143 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1144 break;
1145 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1146 MonoGSharedVtMethodInfo *info;
1147 MonoGSharedVtMethodInfo *oinfo;
1148 int i;
1150 oinfo = patch_info->data.gsharedvt_method;
1151 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1152 res->data.gsharedvt_method = info;
1153 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1154 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1155 for (i = 0; i < oinfo->num_entries; ++i) {
1156 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1157 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1159 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1161 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1162 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1163 break;
1165 case MONO_PATCH_INFO_VIRT_METHOD: {
1166 MonoJumpInfoVirtMethod *info;
1167 MonoJumpInfoVirtMethod *oinfo;
1169 oinfo = patch_info->data.virt_method;
1170 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1171 res->data.virt_method = info;
1172 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1173 break;
1175 default:
1176 break;
1179 return res;
1182 guint
1183 mono_patch_info_hash (gconstpointer data)
1185 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1186 const MonoJumpInfoType type = ji->type;
1187 guint hash = type << 8;
1189 switch (type) {
1190 case MONO_PATCH_INFO_RVA:
1191 case MONO_PATCH_INFO_LDSTR:
1192 case MONO_PATCH_INFO_LDTOKEN:
1193 case MONO_PATCH_INFO_DECLSEC:
1194 return hash | ji->data.token->token;
1195 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1196 return hash | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1197 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: // Hash on the selector name
1198 case MONO_PATCH_INFO_LDSTR_LIT:
1199 return g_str_hash (ji->data.name);
1200 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1201 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1202 return hash | g_str_hash (ji->data.name);
1203 case MONO_PATCH_INFO_VTABLE:
1204 case MONO_PATCH_INFO_CLASS:
1205 case MONO_PATCH_INFO_IID:
1206 case MONO_PATCH_INFO_ADJUSTED_IID:
1207 case MONO_PATCH_INFO_METHODCONST:
1208 case MONO_PATCH_INFO_METHOD:
1209 case MONO_PATCH_INFO_METHOD_JUMP:
1210 case MONO_PATCH_INFO_METHOD_FTNDESC:
1211 case MONO_PATCH_INFO_IMAGE:
1212 case MONO_PATCH_INFO_ICALL_ADDR:
1213 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1214 case MONO_PATCH_INFO_FIELD:
1215 case MONO_PATCH_INFO_SFLDA:
1216 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1217 case MONO_PATCH_INFO_METHOD_RGCTX:
1218 case MONO_PATCH_INFO_SIGNATURE:
1219 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1220 case MONO_PATCH_INFO_AOT_JIT_INFO:
1221 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1222 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1223 return hash | (gssize)ji->data.target;
1224 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1225 return hash | (gssize)ji->data.gsharedvt->method;
1226 case MONO_PATCH_INFO_RGCTX_FETCH:
1227 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1228 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1229 hash |= e->in_mrgctx | e->info_type | mono_patch_info_hash (e->data);
1230 if (e->in_mrgctx)
1231 return hash | (gssize)e->d.method;
1232 else
1233 return hash | (gssize)e->d.klass;
1235 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1236 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1237 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1238 case MONO_PATCH_INFO_GC_NURSERY_START:
1239 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1240 case MONO_PATCH_INFO_GOT_OFFSET:
1241 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1242 case MONO_PATCH_INFO_AOT_MODULE:
1243 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1244 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1245 return hash;
1246 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1247 return hash | ji->data.uindex;
1248 case MONO_PATCH_INFO_JIT_ICALL_ID:
1249 case MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR:
1250 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1251 return hash | ji->data.index;
1252 case MONO_PATCH_INFO_SWITCH:
1253 return hash | ji->data.table->table_size;
1254 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1255 return hash | (gssize)ji->data.gsharedvt_method->method;
1256 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1257 return hash | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1258 case MONO_PATCH_INFO_VIRT_METHOD: {
1259 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1261 return hash | (gssize)info->klass | (gssize)info->method;
1263 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1264 return hash | mono_signature_hash (ji->data.sig);
1265 default:
1266 printf ("info type: %d\n", ji->type);
1267 mono_print_ji (ji); printf ("\n");
1268 g_assert_not_reached ();
1269 return 0;
1274 * mono_patch_info_equal:
1276 * This might fail to recognize equivalent patches, i.e. floats, so its only
1277 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1278 * in AOT.
1280 gint
1281 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1283 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1284 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1286 MonoJumpInfoType const ji1_type = ji1->type;
1287 MonoJumpInfoType const ji2_type = ji2->type;
1289 if (ji1_type != ji2_type)
1290 return 0;
1292 switch (ji1_type) {
1293 case MONO_PATCH_INFO_RVA:
1294 case MONO_PATCH_INFO_LDSTR:
1295 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1296 case MONO_PATCH_INFO_LDTOKEN:
1297 case MONO_PATCH_INFO_DECLSEC:
1298 return ji1->data.token->image == ji2->data.token->image &&
1299 ji1->data.token->token == ji2->data.token->token &&
1300 ji1->data.token->has_context == ji2->data.token->has_context &&
1301 ji1->data.token->context.class_inst == ji2->data.token->context.class_inst &&
1302 ji1->data.token->context.method_inst == ji2->data.token->context.method_inst;
1303 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1304 case MONO_PATCH_INFO_LDSTR_LIT:
1305 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1306 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1307 return g_str_equal (ji1->data.name, ji2->data.name);
1308 case MONO_PATCH_INFO_RGCTX_FETCH:
1309 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1310 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1311 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1313 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);
1315 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1316 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1317 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1319 return c1->sig == c2->sig && c1->method == c2->method;
1321 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1322 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1323 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1324 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;
1325 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1326 return ji1->data.uindex == ji2->data.uindex;
1327 case MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR:
1328 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1329 return ji1->data.index == ji2->data.index;
1330 case MONO_PATCH_INFO_JIT_ICALL_ID:
1331 return ji1->data.jit_icall_id == ji2->data.jit_icall_id;
1332 case MONO_PATCH_INFO_VIRT_METHOD:
1333 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1334 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1335 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig);
1336 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1337 return 1;
1340 return ji1->data.target == ji2->data.target;
1343 gpointer
1344 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1346 unsigned char *ip = patch_info->ip.i + code;
1347 gconstpointer target = NULL;
1349 error_init (error);
1351 switch (patch_info->type) {
1352 case MONO_PATCH_INFO_BB:
1354 * FIXME: This could be hit for methods without a prolog. Should use -1
1355 * but too much code depends on a 0 initial value.
1357 //g_assert (patch_info->data.bb->native_offset);
1358 target = patch_info->data.bb->native_offset + code;
1359 break;
1360 case MONO_PATCH_INFO_ABS:
1361 target = patch_info->data.target;
1362 break;
1363 case MONO_PATCH_INFO_LABEL:
1364 target = patch_info->data.inst->inst_c0 + code;
1365 break;
1366 case MONO_PATCH_INFO_IP:
1367 target = ip;
1368 break;
1369 case MONO_PATCH_INFO_METHOD_REL:
1370 target = code + patch_info->data.offset;
1371 break;
1372 case MONO_PATCH_INFO_JIT_ICALL_ID: {
1373 MonoJitICallInfo * const mi = mono_find_jit_icall_info (patch_info->data.jit_icall_id);
1374 g_assertf (mi, "unknown MONO_PATCH_INFO_JIT_ICALL_ID %d", (int)patch_info->data.jit_icall_id);
1375 target = mono_icall_get_wrapper (mi);
1376 break;
1378 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1379 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1380 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1381 g_assertf (mi, "unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1382 target = mi->func;
1383 break;
1385 case MONO_PATCH_INFO_METHOD_JUMP:
1386 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1387 if (!mono_error_ok (error))
1388 return NULL;
1389 break;
1390 case MONO_PATCH_INFO_METHOD:
1391 if (patch_info->data.method == method) {
1392 target = code;
1393 } else {
1394 /* get the trampoline to the method from the domain */
1395 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1396 if (!mono_error_ok (error))
1397 return NULL;
1399 break;
1400 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1402 * Return an ftndesc for either AOTed code, or for an interp entry.
1404 target = mini_llvmonly_load_method_ftndesc (patch_info->data.method, FALSE, FALSE, error);
1405 return_val_if_nok (error, NULL);
1406 break;
1408 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1409 gpointer code_slot;
1411 mono_domain_lock (domain);
1412 if (!domain_jit_info (domain)->method_code_hash)
1413 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1414 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1415 if (!code_slot) {
1416 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1417 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1419 mono_domain_unlock (domain);
1420 target = code_slot;
1421 break;
1423 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1424 target = (gpointer)&mono_polling_required;
1425 break;
1426 case MONO_PATCH_INFO_SWITCH: {
1427 gpointer *jump_table;
1428 int i;
1429 if (method && method->dynamic) {
1430 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1431 } else {
1432 if (mono_aot_only) {
1433 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1434 } else {
1435 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1439 for (i = 0; i < patch_info->data.table->table_size; i++) {
1440 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1443 target = jump_table;
1444 break;
1446 case MONO_PATCH_INFO_METHODCONST:
1447 case MONO_PATCH_INFO_CLASS:
1448 case MONO_PATCH_INFO_IMAGE:
1449 case MONO_PATCH_INFO_FIELD:
1450 case MONO_PATCH_INFO_SIGNATURE:
1451 case MONO_PATCH_INFO_AOT_MODULE:
1452 target = patch_info->data.target;
1453 break;
1454 case MONO_PATCH_INFO_IID:
1455 mono_class_init_internal (patch_info->data.klass);
1456 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1457 break;
1458 case MONO_PATCH_INFO_ADJUSTED_IID:
1459 mono_class_init_internal (patch_info->data.klass);
1460 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1461 break;
1462 case MONO_PATCH_INFO_VTABLE:
1463 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1464 mono_error_assert_ok (error);
1465 break;
1466 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1467 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1469 if (del_tramp->is_virtual)
1470 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1471 else
1472 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1473 break;
1475 case MONO_PATCH_INFO_SFLDA: {
1476 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1477 mono_error_assert_ok (error);
1479 if (mono_class_field_is_special_static (patch_info->data.field)) {
1480 gpointer addr = NULL;
1482 mono_domain_lock (domain);
1483 if (domain->special_static_fields)
1484 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1485 mono_domain_unlock (domain);
1486 g_assert (addr);
1487 return addr;
1490 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (!method || mono_class_needs_cctor_run (vtable->klass, method)))
1491 /* Done by the generated code */
1493 else {
1494 if (run_cctors) {
1495 if (!mono_runtime_class_init_full (vtable, error)) {
1496 return NULL;
1500 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1501 break;
1503 case MONO_PATCH_INFO_RVA: {
1504 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1505 guint32 rva;
1507 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1508 target = mono_image_rva_map (patch_info->data.token->image, rva);
1509 break;
1511 case MONO_PATCH_INFO_R4:
1512 case MONO_PATCH_INFO_R8:
1513 target = patch_info->data.target;
1514 break;
1515 case MONO_PATCH_INFO_EXC_NAME:
1516 target = patch_info->data.name;
1517 break;
1518 case MONO_PATCH_INFO_LDSTR:
1519 target =
1520 mono_ldstr_checked (domain, patch_info->data.token->image,
1521 mono_metadata_token_index (patch_info->data.token->token), error);
1522 break;
1523 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1524 gpointer handle;
1525 MonoClass *handle_class;
1527 handle = mono_ldtoken_checked (patch_info->data.token->image,
1528 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1529 if (!mono_error_ok (error))
1530 return NULL;
1531 mono_class_init_internal (handle_class);
1532 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType *)handle));
1534 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1535 if (!mono_error_ok (error))
1536 return NULL;
1537 break;
1539 case MONO_PATCH_INFO_LDTOKEN: {
1540 gpointer handle;
1541 MonoClass *handle_class;
1543 handle = mono_ldtoken_checked (patch_info->data.token->image,
1544 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1545 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1546 mono_class_init_internal (handle_class);
1548 target = handle;
1549 break;
1551 case MONO_PATCH_INFO_DECLSEC:
1552 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1553 break;
1554 case MONO_PATCH_INFO_ICALL_ADDR:
1555 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1556 /* run_cctors == 0 -> AOT */
1557 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1558 if (run_cctors) {
1559 target = mono_lookup_pinvoke_call_internal (patch_info->data.method, error);
1560 if (!target) {
1561 if (mono_aot_only)
1562 return NULL;
1563 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));
1565 } else {
1566 target = NULL;
1568 } else {
1569 target = mono_lookup_internal_call (patch_info->data.method);
1571 if (!target && run_cctors)
1572 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1574 break;
1575 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1576 target = mono_thread_interruption_request_flag ();
1577 break;
1578 case MONO_PATCH_INFO_METHOD_RGCTX:
1579 target = mini_method_get_rgctx (patch_info->data.method);
1580 break;
1581 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1582 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1584 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1585 break;
1587 case MONO_PATCH_INFO_BB_OVF:
1588 case MONO_PATCH_INFO_EXC_OVF:
1589 case MONO_PATCH_INFO_GOT_OFFSET:
1590 case MONO_PATCH_INFO_NONE:
1591 break;
1592 case MONO_PATCH_INFO_RGCTX_FETCH: {
1593 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1595 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1596 break;
1598 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1599 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1600 if (!run_cctors)
1601 /* AOT, not needed */
1602 target = NULL;
1603 else
1604 target = mono_arch_get_seq_point_info (domain, code);
1605 break;
1606 #endif
1607 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1608 int card_table_shift_bits;
1609 gpointer card_table_mask;
1611 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1612 break;
1614 case MONO_PATCH_INFO_GC_NURSERY_START: {
1615 int shift_bits;
1616 size_t size;
1618 target = mono_gc_get_nursery (&shift_bits, &size);
1619 break;
1621 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1622 int shift_bits;
1623 size_t size;
1625 mono_gc_get_nursery (&shift_bits, &size);
1627 target = (gpointer)(gssize)shift_bits;
1628 break;
1630 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1631 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1632 break;
1634 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1635 target = NULL;
1636 break;
1638 case MONO_PATCH_INFO_LDSTR_LIT: {
1639 int len;
1640 char *s;
1642 len = strlen ((const char *)patch_info->data.target);
1643 s = (char *)mono_domain_alloc0 (domain, len + 1);
1644 memcpy (s, patch_info->data.target, len);
1645 target = s;
1647 break;
1649 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1650 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1651 break;
1652 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1653 target = (gpointer)mono_tls_get_tls_getter ((MonoTlsKey)patch_info->data.index);
1654 break;
1655 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1656 target = (gpointer)mono_tls_get_tls_setter ((MonoTlsKey)patch_info->data.index);
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_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2199 g_assert (mi);
2201 * We need to make sure this wrapper
2202 * is compiled because it might end up
2203 * in an (M)RGCTX if generic sharing
2204 * is enabled, and would be called
2205 * indirectly. If it were a
2206 * trampoline we'd try to patch that
2207 * indirect call, which is not
2208 * possible.
2210 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2211 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2212 if (mono_llvm_only) {
2213 nm = mono_marshal_get_delegate_invoke (method, NULL);
2214 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2215 return_val_if_nok (error, NULL);
2216 return mono_get_addr_from_ftnptr (compiled_ptr);
2219 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2220 if (mono_use_interpreter)
2221 return NULL;
2223 return mono_create_delegate_trampoline (target_domain, method->klass);
2224 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2225 nm = mono_marshal_get_delegate_begin_invoke (method);
2226 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2227 return_val_if_nok (error, NULL);
2228 return mono_get_addr_from_ftnptr (compiled_ptr);
2229 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2230 nm = mono_marshal_get_delegate_end_invoke (method);
2231 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2232 return_val_if_nok (error, NULL);
2233 return mono_get_addr_from_ftnptr (compiled_ptr);
2237 full_name = mono_method_full_name (method, TRUE);
2238 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2239 g_free (full_name);
2240 return NULL;
2243 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2244 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2246 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2247 static MonoTrampInfo *in_tinfo, *out_tinfo;
2248 MonoTrampInfo *tinfo;
2249 MonoJitInfo *jinfo;
2250 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2252 if (is_in && in_tinfo)
2253 return in_tinfo->code;
2254 else if (!is_in && out_tinfo)
2255 return out_tinfo->code;
2258 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2259 * works.
2260 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2262 if (mono_ee_features.use_aot_trampolines)
2263 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2264 else
2265 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2266 jinfo = create_jit_info_for_trampoline (method, tinfo);
2267 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2268 if (is_in)
2269 in_tinfo = tinfo;
2270 else
2271 out_tinfo = tinfo;
2272 return tinfo->code;
2276 return NULL;
2279 static gpointer
2280 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2282 MonoDomain *target_domain, *domain = mono_domain_get ();
2283 MonoJitInfo *info;
2284 gpointer code = NULL, p;
2285 MonoJitInfo *ji;
2286 MonoJitICallInfo *callinfo = NULL;
2287 WrapperInfo *winfo = NULL;
2288 gboolean use_interp = FALSE;
2290 error_init (error);
2292 if (mono_ee_features.force_use_interpreter && !jit_only)
2293 use_interp = TRUE;
2294 if (!use_interp && mono_interp_only_classes) {
2295 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2296 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2297 use_interp = TRUE;
2300 if (use_interp) {
2301 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2302 if (code)
2303 return code;
2306 if (mono_llvm_only)
2307 /* Should be handled by the caller */
2308 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2311 * ICALL wrappers are handled specially, since there is only one copy of them
2312 * shared by all appdomains.
2314 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2315 winfo = mono_marshal_get_wrapper_info (method);
2316 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2317 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2318 g_assert (callinfo);
2320 /* Must be domain neutral since there is only one copy */
2321 opt |= MONO_OPT_SHARED;
2322 } else {
2323 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2324 opt &= ~MONO_OPT_SHARED;
2327 if (opt & MONO_OPT_SHARED)
2328 target_domain = mono_get_root_domain ();
2329 else
2330 target_domain = domain;
2332 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2333 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2335 g_assert (info);
2336 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2337 MonoGenericContext *ctx = NULL;
2338 if (method->is_inflated)
2339 ctx = mono_method_get_context (method);
2340 method = info->d.synchronized_inner.method;
2341 if (ctx) {
2342 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2343 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2348 lookup_start:
2349 info = lookup_method (target_domain, method);
2350 if (info) {
2351 /* We can't use a domain specific method in another domain */
2352 if (! ((domain != target_domain) && !info->domain_neutral)) {
2353 MonoVTable *vtable;
2355 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2356 vtable = mono_class_vtable_checked (domain, method->klass, error);
2357 if (!is_ok (error))
2358 return NULL;
2359 g_assert (vtable);
2360 if (!mono_runtime_class_init_full (vtable, error))
2361 return NULL;
2362 return mono_create_ftnptr (target_domain, info->code_start);
2366 #ifdef MONO_USE_AOT_COMPILER
2367 if (opt & MONO_OPT_AOT) {
2368 MonoDomain *domain = NULL;
2370 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2371 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2372 g_assert (info);
2373 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2374 /* AOT'd wrappers for interp must be owned by root domain */
2375 domain = mono_get_root_domain ();
2378 if (!domain)
2379 domain = mono_domain_get ();
2381 mono_class_init_internal (method->klass);
2383 code = mono_aot_get_method (domain, method, error);
2384 if (code) {
2385 MonoVTable *vtable;
2387 if (mono_gc_is_critical_method (method)) {
2389 * The suspend code needs to be able to lookup these methods by ip in async context,
2390 * so preload their jit info.
2392 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2393 g_assert (ji);
2397 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2398 * This is not a problem, since it will be initialized when the method is first
2399 * called by init_method ().
2401 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2402 vtable = mono_class_vtable_checked (domain, method->klass, error);
2403 mono_error_assert_ok (error);
2404 if (!mono_runtime_class_init_full (vtable, error))
2405 return NULL;
2408 if (!is_ok (error))
2409 return NULL;
2411 #endif
2413 if (!code) {
2414 code = compile_special (method, target_domain, error);
2416 if (!mono_error_ok (error))
2417 return NULL;
2420 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER) {
2421 if (mono_llvm_only) {
2422 /* Signal to the caller that AOTed code is not found */
2423 return NULL;
2425 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2427 if (!mono_error_ok (error))
2428 return NULL;
2431 if (!code) {
2432 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2433 char *full_name = mono_type_get_full_name (method->klass);
2434 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2435 g_free (full_name);
2436 return NULL;
2439 if (mono_aot_only) {
2440 char *fullname = mono_method_get_full_name (method);
2441 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);
2442 g_free (fullname);
2444 return NULL;
2447 if (wait_or_register_method_to_compile (method, target_domain))
2448 goto lookup_start;
2449 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2450 unregister_method_for_compile (method, target_domain);
2452 if (!mono_error_ok (error))
2453 return NULL;
2455 if (!code && mono_llvm_only) {
2456 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2457 g_assert_not_reached ();
2460 if (!code)
2461 return NULL;
2463 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2464 #ifndef HOST_WASM
2465 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2466 MonoDomain *d;
2469 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2471 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2472 g_assert (ji);
2474 #endif
2476 p = mono_create_ftnptr (target_domain, code);
2478 if (callinfo) {
2479 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2480 mono_loader_lock ();
2481 mono_jit_lock ();
2482 if (!callinfo->wrapper) {
2483 callinfo->wrapper = p;
2484 mono_register_jit_icall_wrapper (callinfo, p);
2486 mono_jit_unlock ();
2487 mono_loader_unlock ();
2490 return p;
2493 gpointer
2494 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2496 gpointer code;
2498 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2499 return code;
2503 * mono_jit_compile_method_jit_only:
2505 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2507 gpointer
2508 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2510 gpointer code;
2512 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2513 return code;
2516 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2517 static void
2518 invalidated_delegate_trampoline (char *desc)
2520 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2521 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2522 desc);
2524 #endif
2527 * mono_jit_free_method:
2529 * Free all memory allocated by the JIT for METHOD.
2531 static void
2532 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2534 MonoJitDynamicMethodInfo *ji;
2535 gboolean destroy = TRUE, removed;
2536 GHashTableIter iter;
2537 MonoJumpList *jlist;
2538 MonoJitDomainInfo *info = domain_jit_info (domain);
2540 g_assert (method->dynamic);
2542 if (mono_use_interpreter) {
2543 mono_domain_jit_code_hash_lock (domain);
2544 /* InterpMethod is allocated in the domain mempool. We might haven't
2545 * allocated an InterpMethod for this instance yet */
2546 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2547 mono_domain_jit_code_hash_unlock (domain);
2550 mono_domain_lock (domain);
2551 ji = mono_dynamic_code_hash_lookup (domain, method);
2552 mono_domain_unlock (domain);
2554 if (!ji)
2555 return;
2557 mono_debug_remove_method (method, domain);
2558 mono_lldb_remove_method (domain, method, ji);
2560 mono_domain_lock (domain);
2561 g_hash_table_remove (info->dynamic_code_hash, method);
2562 mono_domain_jit_code_hash_lock (domain);
2563 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2564 g_assert (removed);
2565 mono_domain_jit_code_hash_unlock (domain);
2566 g_hash_table_remove (info->jump_trampoline_hash, method);
2567 g_hash_table_remove (info->seq_points, method);
2569 ji->ji->seq_points = NULL;
2571 /* requires the domain lock - took above */
2572 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2574 /* Remove jump targets in this method */
2575 g_hash_table_iter_init (&iter, info->jump_target_hash);
2576 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2577 GSList *tmp, *remove;
2579 remove = NULL;
2580 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2581 guint8 *ip = (guint8 *)tmp->data;
2583 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2584 remove = g_slist_prepend (remove, tmp);
2586 for (tmp = remove; tmp; tmp = tmp->next) {
2587 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2589 g_slist_free (remove);
2591 mono_domain_unlock (domain);
2593 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2594 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2596 * Instead of freeing the code, change it to call an error routine
2597 * so people can fix their code.
2599 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2600 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2602 g_free (type);
2603 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2604 destroy = FALSE;
2606 #endif
2609 * This needs to be done before freeing code_mp, since the code address is the
2610 * key in the table, so if we free the code_mp first, another thread can grab the
2611 * same code address and replace our entry in the table.
2613 mono_jit_info_table_remove (domain, ji->ji);
2615 if (destroy)
2616 mono_code_manager_destroy (ji->code_mp);
2617 g_free (ji);
2620 gpointer
2621 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2623 gpointer code;
2624 MonoJitInfo *ji;
2626 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2627 if (!code) {
2628 ERROR_DECL (oerror);
2630 /* Might be AOTed code */
2631 mono_class_init_internal (method->klass);
2632 code = mono_aot_get_method (domain, method, oerror);
2633 if (code) {
2634 mono_error_assert_ok (oerror);
2635 ji = mono_jit_info_table_find (domain, code);
2636 } else {
2637 if (!is_ok (oerror))
2638 mono_error_cleanup (oerror);
2640 /* Might be interpreted */
2641 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2645 *out_ji = ji;
2647 return code;
2650 gpointer
2651 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2653 MonoDomain *target_domain;
2654 MonoJitInfo *info;
2656 if (default_opt & MONO_OPT_SHARED)
2657 target_domain = mono_get_root_domain ();
2658 else
2659 target_domain = domain;
2661 info = lookup_method (target_domain, method);
2662 if (info) {
2663 /* We can't use a domain specific method in another domain */
2664 if (! ((domain != target_domain) && !info->domain_neutral)) {
2665 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2666 if (ji)
2667 *ji = info;
2668 return info->code_start;
2672 if (ji)
2673 *ji = NULL;
2674 return NULL;
2677 static guint32 bisect_opt = 0;
2678 static GHashTable *bisect_methods_hash = NULL;
2680 void
2681 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2683 FILE *file;
2684 char method_name [2048];
2686 bisect_opt = opt;
2687 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2688 g_assert (bisect_methods_hash);
2690 file = fopen (method_list_filename, "r");
2691 g_assert (file);
2693 while (fgets (method_name, sizeof (method_name), file)) {
2694 size_t len = strlen (method_name);
2695 g_assert (len > 0);
2696 g_assert (method_name [len - 1] == '\n');
2697 method_name [len - 1] = 0;
2698 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2700 g_assert (feof (file));
2703 gboolean mono_do_single_method_regression = FALSE;
2704 guint32 mono_single_method_regression_opt = 0;
2705 MonoMethod *mono_current_single_method;
2706 GSList *mono_single_method_list;
2707 GHashTable *mono_single_method_hash;
2709 guint32
2710 mono_get_optimizations_for_method (MonoMethod *method, guint32 opt)
2712 g_assert (method);
2714 if (bisect_methods_hash) {
2715 char *name = mono_method_full_name (method, TRUE);
2716 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2717 g_free (name);
2718 if (res)
2719 return opt | bisect_opt;
2721 if (!mono_do_single_method_regression)
2722 return opt;
2723 if (!mono_current_single_method) {
2724 if (!mono_single_method_hash)
2725 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2726 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2727 g_hash_table_insert (mono_single_method_hash, method, method);
2728 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2730 return opt;
2732 if (method == mono_current_single_method)
2733 return mono_single_method_regression_opt;
2734 return opt;
2737 gpointer
2738 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2740 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2743 typedef struct {
2744 MonoMethod *method;
2745 gpointer compiled_method;
2746 gpointer runtime_invoke;
2747 MonoVTable *vtable;
2748 MonoDynCallInfo *dyn_call_info;
2749 MonoClass *ret_box_class;
2750 MonoMethodSignature *sig;
2751 gboolean gsharedvt_invoke;
2752 gboolean use_interp;
2753 gpointer *wrapper_arg;
2754 } RuntimeInvokeInfo;
2756 static RuntimeInvokeInfo*
2757 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2759 MonoMethod *invoke;
2760 RuntimeInvokeInfo *info;
2762 info = g_new0 (RuntimeInvokeInfo, 1);
2763 info->compiled_method = compiled_method;
2764 info->use_interp = use_interp;
2765 if (mono_llvm_only && method->string_ctor)
2766 info->sig = mono_marshal_get_string_ctor_signature (method);
2767 else
2768 info->sig = mono_method_signature_internal (method);
2770 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2771 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2772 if (!mono_error_ok (error))
2773 return NULL;
2774 g_assert (info->vtable);
2776 MonoMethodSignature *sig = info->sig;
2777 MonoType *ret_type;
2780 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2781 * in full-aot mode, so we use a slower, but more generic wrapper if
2782 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2784 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2785 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2786 gboolean supported = TRUE;
2787 int i;
2789 if (method->string_ctor)
2790 sig = mono_marshal_get_string_ctor_signature (method);
2792 for (i = 0; i < sig->param_count; ++i) {
2793 MonoType *t = sig->params [i];
2795 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
2796 supported = FALSE;
2799 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2800 supported = FALSE;
2802 if (supported) {
2803 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2804 if (mini_debug_options.dyn_runtime_invoke)
2805 g_assert (info->dyn_call_info);
2808 #endif
2810 ret_type = sig->ret;
2811 switch (ret_type->type) {
2812 case MONO_TYPE_VOID:
2813 break;
2814 case MONO_TYPE_I1:
2815 case MONO_TYPE_U1:
2816 case MONO_TYPE_I2:
2817 case MONO_TYPE_U2:
2818 case MONO_TYPE_I4:
2819 case MONO_TYPE_U4:
2820 case MONO_TYPE_I:
2821 case MONO_TYPE_U:
2822 case MONO_TYPE_I8:
2823 case MONO_TYPE_U8:
2824 case MONO_TYPE_BOOLEAN:
2825 case MONO_TYPE_CHAR:
2826 case MONO_TYPE_R4:
2827 case MONO_TYPE_R8:
2828 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2829 break;
2830 case MONO_TYPE_PTR:
2831 info->ret_box_class = mono_defaults.int_class;
2832 break;
2833 case MONO_TYPE_STRING:
2834 case MONO_TYPE_CLASS:
2835 case MONO_TYPE_ARRAY:
2836 case MONO_TYPE_SZARRAY:
2837 case MONO_TYPE_OBJECT:
2838 break;
2839 case MONO_TYPE_GENERICINST:
2840 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2841 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2842 break;
2843 case MONO_TYPE_VALUETYPE:
2844 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2845 break;
2846 default:
2847 g_assert_not_reached ();
2848 break;
2851 if (info->use_interp)
2852 return info;
2854 if (!info->dyn_call_info) {
2855 if (mono_llvm_only) {
2856 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2857 g_assert_not_reached ();
2858 #endif
2859 info->gsharedvt_invoke = TRUE;
2860 if (!callee_gsharedvt) {
2861 /* Invoke a gsharedvt out wrapper instead */
2862 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2863 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2865 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2866 info->wrapper_arg [0] = mini_llvmonly_add_method_wrappers (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2868 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2869 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2870 g_free (wrapper_sig);
2872 info->compiled_method = mono_jit_compile_method (wrapper, error);
2873 if (!mono_error_ok (error)) {
2874 g_free (info);
2875 return NULL;
2877 } else {
2878 /* Gsharedvt methods can be invoked the same way */
2879 /* The out wrapper has the same signature as the compiled gsharedvt method */
2880 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2882 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
2884 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2885 g_free (wrapper_sig);
2888 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2889 if (!mono_error_ok (error)) {
2890 g_free (info);
2891 return NULL;
2895 return info;
2898 static MonoObject*
2899 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2901 MonoMethodSignature *sig = info->sig;
2902 MonoDomain *domain = mono_domain_get ();
2903 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2904 gpointer *args;
2905 gpointer retval_ptr;
2906 guint8 retval [256];
2907 gpointer *param_refs;
2908 int i, pindex;
2910 error_init (error);
2912 g_assert (info->gsharedvt_invoke);
2915 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2916 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2917 * signatures, so we only have to generate runtime invoke wrappers for these
2918 * signatures.
2919 * This code also handles invocation of gsharedvt methods directly, no
2920 * out wrappers are used in that case.
2922 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2923 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2924 pindex = 0;
2926 * The runtime invoke wrappers expects pointers to primitive types, so have to
2927 * use indirections.
2929 if (sig->hasthis)
2930 args [pindex ++] = &obj;
2931 if (sig->ret->type != MONO_TYPE_VOID) {
2932 retval_ptr = (gpointer)&retval;
2933 args [pindex ++] = &retval_ptr;
2935 for (i = 0; i < sig->param_count; ++i) {
2936 MonoType *t = sig->params [i];
2938 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
2939 MonoClass *klass = mono_class_from_mono_type_internal (t);
2940 guint8 *nullable_buf;
2941 int size;
2943 size = mono_class_value_size (klass, NULL);
2944 nullable_buf = g_alloca (size);
2945 g_assert (nullable_buf);
2947 /* The argument pointed to by params [i] is either a boxed vtype or null */
2948 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2949 params [i] = nullable_buf;
2952 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2953 param_refs [i] = params [i];
2954 params [i] = &(param_refs [i]);
2956 args [pindex ++] = &params [i];
2958 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2959 args [pindex ++] = &info->wrapper_arg;
2961 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2963 runtime_invoke (NULL, args, exc, info->compiled_method);
2964 if (exc && *exc)
2965 return NULL;
2967 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2968 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2969 else
2970 return *(MonoObject**)retval;
2974 * mono_jit_runtime_invoke:
2975 * \param method: the method to invoke
2976 * \param obj: this pointer
2977 * \param params: array of parameter values.
2978 * \param exc: Set to the exception raised in the managed method.
2979 * \param error: error or caught exception object
2980 * If \p exc is NULL, \p error is thrown instead.
2981 * If coop is enabled, \p exc argument is ignored -
2982 * all exceptions are caught and propagated through \p error
2984 static MonoObject*
2985 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2987 MonoMethod *invoke, *callee;
2988 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2989 MonoDomain *domain = mono_domain_get ();
2990 MonoJitDomainInfo *domain_info;
2991 RuntimeInvokeInfo *info, *info2;
2992 MonoJitInfo *ji = NULL;
2993 gboolean callee_gsharedvt = FALSE;
2995 if (mono_ee_features.force_use_interpreter)
2996 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
2998 error_init (error);
2999 if (exc)
3000 *exc = NULL;
3002 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
3003 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3004 return NULL;
3007 domain_info = domain_jit_info (domain);
3009 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3011 if (!info) {
3012 if (mono_security_core_clr_enabled ()) {
3014 * This might be redundant since mono_class_vtable () already does this,
3015 * but keep it just in case for moonlight.
3017 mono_class_setup_vtable (method->klass);
3018 if (mono_class_has_failure (method->klass)) {
3019 mono_error_set_for_class_failure (error, method->klass);
3020 if (exc)
3021 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3022 return NULL;
3026 gpointer compiled_method;
3028 callee = method;
3029 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3030 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3032 * Array Get/Set/Address methods. The JIT implements them using inline code
3033 * inside the runtime invoke wrappers, so no need to compile them.
3035 if (mono_aot_only) {
3037 * Call a wrapper, since the runtime invoke wrapper was not generated.
3039 MonoMethod *wrapper;
3041 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3042 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3043 callee = wrapper;
3044 } else {
3045 callee = NULL;
3049 gboolean use_interp = FALSE;
3051 if (callee) {
3052 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3053 if (!compiled_method) {
3054 g_assert (!mono_error_ok (error));
3056 if (mono_use_interpreter)
3057 use_interp = TRUE;
3058 else
3059 return NULL;
3060 } else {
3061 if (mono_llvm_only) {
3062 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3063 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3064 if (callee_gsharedvt)
3065 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3068 if (!callee_gsharedvt)
3069 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3071 } else {
3072 compiled_method = NULL;
3075 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3076 if (!mono_error_ok (error))
3077 return NULL;
3079 mono_domain_lock (domain);
3080 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3081 mono_domain_unlock (domain);
3082 if (info2) {
3083 g_free (info);
3084 info = info2;
3089 * We need this here because mono_marshal_get_runtime_invoke can place
3090 * the helper method in System.Object and not the target class.
3092 if (!mono_runtime_class_init_full (info->vtable, error)) {
3093 if (exc)
3094 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3095 return NULL;
3098 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3099 we always catch the exception and propagate it through the MonoError */
3100 gboolean catchExcInMonoError =
3101 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3102 MonoObject *invoke_exc = NULL;
3103 if (catchExcInMonoError)
3104 exc = &invoke_exc;
3106 /* The wrappers expect this to be initialized to NULL */
3107 if (exc)
3108 *exc = NULL;
3110 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3111 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3112 if (info->dyn_call_info) {
3113 if (!dyn_runtime_invoke) {
3114 mono_domain_lock (domain);
3116 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3117 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3118 if (!dyn_runtime_invoke && mono_use_interpreter) {
3119 info->use_interp = TRUE;
3120 info->dyn_call_info = NULL;
3121 } else if (!mono_error_ok (error)) {
3122 mono_domain_unlock (domain);
3123 return NULL;
3125 mono_domain_unlock (domain);
3128 if (info->dyn_call_info) {
3129 MonoMethodSignature *sig = mono_method_signature_internal (method);
3130 gpointer *args;
3131 int i, pindex, buf_size;
3132 guint8 *buf;
3133 guint8 retval [256];
3135 /* Convert the arguments to the format expected by start_dyn_call () */
3136 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3137 pindex = 0;
3138 if (sig->hasthis)
3139 args [pindex ++] = &obj;
3140 for (i = 0; i < sig->param_count; ++i) {
3141 MonoType *t = sig->params [i];
3143 if (t->byref) {
3144 args [pindex ++] = &params [i];
3145 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3146 args [pindex ++] = &params [i];
3147 } else {
3148 args [pindex ++] = params [i];
3152 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3154 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3155 buf = g_alloca (buf_size);
3156 memset (buf, 0, buf_size);
3157 g_assert (buf);
3159 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3161 dyn_runtime_invoke (buf, exc, info->compiled_method);
3162 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3164 if (catchExcInMonoError && *exc != NULL) {
3165 mono_error_set_exception_instance (error, (MonoException*) *exc);
3166 return NULL;
3169 if (info->ret_box_class)
3170 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3171 else
3172 return *(MonoObject**)retval;
3174 #endif
3176 MonoObject *result;
3178 if (info->use_interp) {
3179 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3180 return_val_if_nok (error, NULL);
3181 } else if (mono_llvm_only) {
3182 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3183 if (!is_ok (error))
3184 return NULL;
3185 } else {
3186 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3188 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3190 if (catchExcInMonoError && *exc != NULL) {
3191 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3192 mono_error_set_exception_instance (error, (MonoException*) *exc);
3194 return result;
3197 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3199 MonoException *exc = NULL;
3200 MonoJitInfo *ji;
3201 MonoContext mctx;
3202 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3203 MONO_SIG_HANDLER_GET_CONTEXT;
3205 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3207 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3209 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3210 if (mono_arch_is_int_overflow (ctx, info))
3212 * The spec says this throws ArithmeticException, but MS throws the derived
3213 * OverflowException.
3215 exc = mono_get_exception_overflow ();
3216 else
3217 exc = mono_get_exception_divide_by_zero ();
3218 #else
3219 exc = mono_get_exception_divide_by_zero ();
3220 #endif
3222 if (!ji) {
3223 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3224 goto exit;
3226 mono_sigctx_to_monoctx (ctx, &mctx);
3227 mono_handle_native_crash ("SIGFPE", &mctx, info);
3228 if (mono_do_crash_chaining) {
3229 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3230 goto exit;
3234 mono_arch_handle_exception (ctx, exc);
3236 exit:
3237 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3240 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3242 MonoContext mctx;
3243 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3244 MONO_SIG_HANDLER_GET_CONTEXT;
3246 if (mono_runtime_get_no_exec ())
3247 exit (1);
3249 mono_sigctx_to_monoctx (ctx, &mctx);
3250 mono_handle_native_crash ("SIGILL", &mctx, info);
3251 if (mono_do_crash_chaining) {
3252 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3253 return;
3256 g_assert_not_reached ();
3259 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3261 #define HAVE_SIG_INFO
3262 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3264 #ifdef MONO_SIG_HANDLER_DEBUG
3265 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3266 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3267 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3268 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3269 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3270 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3271 #endif
3273 #endif
3275 static gboolean
3276 is_addr_implicit_null_check (void *addr)
3278 /* implicit null checks are only expected to work on the first page. larger
3279 * offsets are expected to have an explicit null check */
3280 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3283 // This function is separate from mono_sigsegv_signal_handler
3284 // so debug_fault_addr can be seen in debugger stacks.
3285 #ifdef MONO_SIG_HANDLER_DEBUG
3286 MONO_NEVER_INLINE
3287 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3288 #else
3289 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3290 #endif
3292 MonoJitInfo *ji = NULL;
3293 MonoDomain *domain = mono_domain_get ();
3294 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3295 gpointer fault_addr = NULL;
3296 MonoContext mctx;
3298 #ifdef HAVE_SIG_INFO
3299 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3300 #else
3301 void *info = NULL;
3302 #endif
3303 MONO_SIG_HANDLER_GET_CONTEXT;
3305 mono_sigctx_to_monoctx (ctx, &mctx);
3307 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3308 if (mono_arch_is_single_step_event (info, ctx)) {
3309 mini_get_dbg_callbacks ()->single_step_event (ctx);
3310 return;
3311 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3312 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3313 return;
3315 #endif
3317 #if defined(HAVE_SIG_INFO)
3318 #if !defined(HOST_WIN32)
3319 fault_addr = info->si_addr;
3320 if (mono_aot_is_pagefault (info->si_addr)) {
3321 mono_aot_handle_pagefault (info->si_addr);
3322 return;
3324 #endif
3326 /* The thread might no be registered with the runtime */
3327 if (!mono_domain_get () || !jit_tls) {
3328 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3329 return;
3330 mono_handle_native_crash ("SIGSEGV", &mctx, info);
3331 if (mono_do_crash_chaining) {
3332 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3333 return;
3336 #endif
3338 if (domain)
3339 ji = mono_jit_info_table_find_internal (domain, mono_arch_ip_from_context (ctx), TRUE, TRUE);
3341 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3342 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3343 return;
3345 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3346 fault_addr = info->si_addr;
3347 if (fault_addr == NULL) {
3348 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3351 if (jit_tls && jit_tls->stack_size &&
3352 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3354 * The hard-guard page has been hit: there is not much we can do anymore
3355 * Print a hopefully clear message and abort.
3357 mono_handle_hard_stack_ovf (jit_tls, ji, &mctx, (guint8*)info->si_addr);
3358 g_assert_not_reached ();
3359 } else {
3360 /* The original handler might not like that it is executed on an altstack... */
3361 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3362 return;
3364 if (is_addr_implicit_null_check (info->si_addr)) {
3365 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3366 } else {
3367 mono_handle_native_crash ("SIGSEGV", &mctx, info);
3370 #else
3372 if (!ji) {
3373 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3374 return;
3376 mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3378 if (mono_do_crash_chaining) {
3379 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3380 return;
3384 if (is_addr_implicit_null_check (fault_addr)) {
3385 mono_arch_handle_exception (ctx, NULL);
3386 } else {
3387 mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3389 #endif
3392 #ifdef MONO_SIG_HANDLER_DEBUG
3394 // This function is separate from mono_sigsegv_signal_handler_debug
3395 // so debug_fault_addr can be seen in debugger stacks.
3396 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3398 #ifdef HOST_WIN32
3399 gpointer const debug_fault_addr = (gpointer)MONO_SIG_HANDLER_GET_INFO () ->ep->ExceptionRecord->ExceptionInformation [1];
3400 #elif defined (HAVE_SIG_INFO)
3401 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3402 #else
3403 #error No extra parameter is passed, not even 0, to avoid any confusion.
3404 #endif
3405 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3408 #endif // MONO_SIG_HANDLER_DEBUG
3410 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3412 MonoException *exc;
3413 MONO_SIG_HANDLER_GET_CONTEXT;
3415 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3417 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3419 mono_arch_handle_exception (ctx, exc);
3421 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3424 #ifndef DISABLE_REMOTING
3425 /* mono_jit_create_remoting_trampoline:
3426 * @method: pointer to the method info
3428 * Creates a trampoline which calls the remoting functions. This
3429 * is used in the vtable of transparent proxies.
3431 * Returns: a pointer to the newly created code
3433 static gpointer
3434 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3436 MonoMethod *nm;
3437 guint8 *addr = NULL;
3439 error_init (error);
3441 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3442 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3443 domain, NULL);
3446 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3447 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3448 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3449 else
3450 nm = method;
3451 return_val_if_nok (error, NULL);
3452 addr = (guint8 *)mono_compile_method_checked (nm, error);
3453 return_val_if_nok (error, NULL);
3454 return mono_get_addr_from_ftnptr (addr);
3456 #endif
3458 static G_GNUC_UNUSED void
3459 no_imt_trampoline (void)
3461 g_assert_not_reached ();
3464 static G_GNUC_UNUSED void
3465 no_vcall_trampoline (void)
3467 g_assert_not_reached ();
3470 static gpointer *vtable_trampolines;
3471 static int vtable_trampolines_size;
3473 gpointer
3474 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3476 int index = slot_index + MONO_IMT_SIZE;
3478 if (mono_llvm_only)
3479 return mini_llvmonly_get_vtable_trampoline (vt, slot_index, index);
3481 g_assert (slot_index >= - MONO_IMT_SIZE);
3482 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3483 mono_jit_lock ();
3484 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3485 int new_size;
3486 gpointer new_table;
3488 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3489 while (new_size <= index)
3490 new_size *= 2;
3491 new_table = g_new0 (gpointer, new_size);
3493 if (vtable_trampolines)
3494 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3495 g_free (vtable_trampolines);
3496 mono_memory_barrier ();
3497 vtable_trampolines = (void **)new_table;
3498 vtable_trampolines_size = new_size;
3500 mono_jit_unlock ();
3503 if (!vtable_trampolines [index])
3504 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3505 return vtable_trampolines [index];
3508 static gpointer
3509 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3511 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3514 static gboolean
3515 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3517 if (mono_llvm_only)
3518 return FALSE;
3520 gpointer *imt = (gpointer*)vt;
3521 imt -= MONO_IMT_SIZE;
3523 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3526 static gpointer
3527 create_delegate_method_ptr (MonoMethod *method, MonoError *error)
3529 gpointer func;
3531 if (method_is_dynamic (method)) {
3532 /* Creating a trampoline would leak memory */
3533 func = mono_compile_method_checked (method, error);
3534 return_val_if_nok (error, NULL);
3535 } else {
3536 gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
3537 return_val_if_nok (error, NULL);
3538 func = mono_create_ftnptr (mono_domain_get (), trampoline);
3540 return func;
3543 static void
3544 mini_init_delegate (MonoDelegateHandle delegate, MonoError *error)
3546 MonoDelegate *del = MONO_HANDLE_RAW (delegate);
3548 if (mono_use_interpreter) {
3549 mini_get_interp_callbacks ()->init_delegate (del, error);
3550 return_if_nok (error);
3553 if (mono_llvm_only) {
3554 g_assert (del->method);
3555 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3556 del->method_ptr = mini_llvmonly_load_method_delegate (del->method, FALSE, FALSE, &del->extra_arg, error);
3557 } else if (!del->method_ptr && !del->interp_method) {
3558 del->method_ptr = create_delegate_method_ptr (del->method, error);
3559 return_if_nok (error);
3563 char*
3564 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3566 int abs_offset;
3568 abs_offset = offset;
3569 if (abs_offset < 0)
3570 abs_offset = - abs_offset;
3571 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3574 gpointer
3575 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3577 gboolean is_virtual_generic, is_interface, load_imt_reg;
3578 int offset, idx;
3580 static guint8 **cache = NULL;
3581 static int cache_size = 0;
3583 if (!method)
3584 return NULL;
3586 if (MONO_TYPE_ISSTRUCT (sig->ret))
3587 return NULL;
3589 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3590 is_interface = mono_class_is_interface (method->klass);
3591 load_imt_reg = is_virtual_generic || is_interface;
3593 if (is_interface)
3594 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3595 else
3596 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3598 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3599 g_assert (idx >= 0);
3601 /* Resize the cache to idx + 1 */
3602 if (cache_size < idx + 1) {
3603 mono_jit_lock ();
3604 if (cache_size < idx + 1) {
3605 guint8 **new_cache;
3606 int new_cache_size = idx + 1;
3608 new_cache = g_new0 (guint8*, new_cache_size);
3609 if (cache)
3610 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3611 g_free (cache);
3613 mono_memory_barrier ();
3614 cache = new_cache;
3615 cache_size = new_cache_size;
3617 mono_jit_unlock ();
3620 if (cache [idx])
3621 return cache [idx];
3623 /* FIXME Support more cases */
3624 if (mono_ee_features.use_aot_trampolines) {
3625 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3626 g_assert (cache [idx]);
3627 } else {
3628 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3630 return cache [idx];
3634 * mini_parse_debug_option:
3635 * @option: The option to parse.
3637 * Parses debug options for the mono runtime. The options are the same as for
3638 * the MONO_DEBUG environment variable.
3641 gboolean
3642 mini_parse_debug_option (const char *option)
3644 // Empty string is ok as consequence of appending ",foo"
3645 // without first checking for empty.
3646 if (*option == 0)
3647 return TRUE;
3649 if (!strcmp (option, "handle-sigint"))
3650 mini_debug_options.handle_sigint = TRUE;
3651 else if (!strcmp (option, "keep-delegates"))
3652 mini_debug_options.keep_delegates = TRUE;
3653 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3654 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3655 else if (!strcmp (option, "collect-pagefault-stats"))
3656 mini_debug_options.collect_pagefault_stats = TRUE;
3657 else if (!strcmp (option, "break-on-unverified"))
3658 mini_debug_options.break_on_unverified = TRUE;
3659 else if (!strcmp (option, "no-gdb-backtrace"))
3660 mini_debug_options.no_gdb_backtrace = TRUE;
3661 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3662 mini_debug_options.suspend_on_native_crash = TRUE;
3663 else if (!strcmp (option, "suspend-on-exception"))
3664 mini_debug_options.suspend_on_exception = TRUE;
3665 else if (!strcmp (option, "suspend-on-unhandled"))
3666 mini_debug_options.suspend_on_unhandled = TRUE;
3667 else if (!strcmp (option, "dont-free-domains"))
3668 mono_dont_free_domains = TRUE;
3669 else if (!strcmp (option, "dyn-runtime-invoke"))
3670 mini_debug_options.dyn_runtime_invoke = TRUE;
3671 else if (!strcmp (option, "gdb"))
3672 mini_debug_options.gdb = TRUE;
3673 else if (!strcmp (option, "lldb"))
3674 mini_debug_options.lldb = TRUE;
3675 else if (!strcmp (option, "llvm-disable-self-init"))
3676 mini_debug_options.llvm_disable_self_init = TRUE;
3677 else if (!strcmp (option, "explicit-null-checks"))
3678 mini_debug_options.explicit_null_checks = TRUE;
3679 else if (!strcmp (option, "gen-seq-points"))
3680 mini_debug_options.gen_sdb_seq_points = TRUE;
3681 else if (!strcmp (option, "gen-compact-seq-points"))
3682 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3683 else if (!strcmp (option, "no-compact-seq-points"))
3684 mini_debug_options.no_seq_points_compact_data = TRUE;
3685 else if (!strcmp (option, "single-imm-size"))
3686 mini_debug_options.single_imm_size = TRUE;
3687 else if (!strcmp (option, "init-stacks"))
3688 mini_debug_options.init_stacks = TRUE;
3689 else if (!strcmp (option, "casts"))
3690 mini_debug_options.better_cast_details = TRUE;
3691 else if (!strcmp (option, "soft-breakpoints"))
3692 mini_debug_options.soft_breakpoints = TRUE;
3693 else if (!strcmp (option, "check-pinvoke-callconv"))
3694 mini_debug_options.check_pinvoke_callconv = TRUE;
3695 else if (!strcmp (option, "use-fallback-tls"))
3696 mini_debug_options.use_fallback_tls = TRUE;
3697 else if (!strcmp (option, "debug-domain-unload"))
3698 mono_enable_debug_domain_unload (TRUE);
3699 else if (!strcmp (option, "partial-sharing"))
3700 mono_set_partial_sharing_supported (TRUE);
3701 else if (!strcmp (option, "align-small-structs"))
3702 mono_align_small_structs = TRUE;
3703 else if (!strcmp (option, "native-debugger-break"))
3704 mini_debug_options.native_debugger_break = TRUE;
3705 else if (!strcmp (option, "disable_omit_fp"))
3706 mini_debug_options.disable_omit_fp = TRUE;
3707 // This is an internal testing feature.
3708 // Every tail. encountered is required to be optimized.
3709 // It is asserted.
3710 else if (!strcmp (option, "test-tailcall-require"))
3711 mini_debug_options.test_tailcall_require = TRUE;
3712 else if (!strcmp (option, "verbose-gdb"))
3713 mini_debug_options.verbose_gdb = TRUE;
3714 else if (!strncmp (option, "thread-dump-dir=", 16))
3715 mono_set_thread_dump_dir(g_strdup(option + 16));
3716 else if (!strncmp (option, "aot-skip=", 9)) {
3717 mini_debug_options.aot_skip_set = TRUE;
3718 mini_debug_options.aot_skip = atoi (option + 9);
3719 } else
3720 return FALSE;
3722 return TRUE;
3725 static void
3726 mini_parse_debug_options (void)
3728 char *options = g_getenv ("MONO_DEBUG");
3729 gchar **args, **ptr;
3731 if (!options)
3732 return;
3734 args = g_strsplit (options, ",", -1);
3735 g_free (options);
3737 for (ptr = args; ptr && *ptr; ptr++) {
3738 const char *arg = *ptr;
3740 if (!mini_parse_debug_option (arg)) {
3741 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3742 // test-tailcall-require is also accepted but not documented.
3743 // empty string is also accepted and ignored as a consequence
3744 // of appending ",foo" without checking for empty.
3745 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'.\n");
3746 exit (1);
3750 g_strfreev (args);
3753 MonoDebugOptions *
3754 mini_get_debug_options (void)
3756 return &mini_debug_options;
3759 static gpointer
3760 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3762 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3763 gpointer* desc = NULL;
3765 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3766 return desc;
3767 #if defined(__mono_ppc64__)
3768 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3770 desc [0] = addr;
3771 desc [1] = NULL;
3772 desc [2] = NULL;
3773 # endif
3774 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3775 return desc;
3776 #else
3777 return addr;
3778 #endif
3781 static gpointer
3782 mini_get_addr_from_ftnptr (gpointer descr)
3784 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3785 return *(gpointer*)descr;
3786 #else
3787 return descr;
3788 #endif
3791 static void
3792 register_jit_stats (void)
3794 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3795 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3796 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3797 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3798 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
3799 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_method_to_ir);
3800 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);
3801 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);
3802 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_long_opts);
3803 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_typechecks);
3804 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop);
3805 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_emulate_ops);
3806 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches);
3807 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs);
3808 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce);
3809 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_alias_analysis);
3810 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_if_conversion);
3811 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_bb_ordering);
3812 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compile_dominator_info);
3813 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compute_natural_loops);
3814 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_insert_safepoints);
3815 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_compute);
3816 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_cprop);
3817 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_deadce);
3818 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_perform_abc_removal);
3819 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_remove);
3820 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop2);
3821 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs2);
3822 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce2);
3823 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches2);
3824 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_vtype_opts);
3825 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);
3826 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);
3827 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_analyze_liveness);
3828 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_linear_scan);
3829 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_arch_allocate_vars);
3830 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_spill_global_vars);
3831 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop3);
3832 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce3);
3833 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_codegen);
3834 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_create_jit_info);
3835 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);
3836 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);
3837 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_time);
3838 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3839 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3840 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3841 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3842 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3843 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3844 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3845 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3846 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3847 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3848 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3849 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3850 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3851 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3852 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3853 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3854 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3855 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3858 static void runtime_invoke_info_free (gpointer value);
3860 static gint
3861 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3863 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3864 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3866 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3869 static guint
3870 class_method_pair_hash (gconstpointer data)
3872 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3874 return (gsize)pair->klass ^ (gsize)pair->method;
3877 static void
3878 mini_create_jit_domain_info (MonoDomain *domain)
3880 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3882 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3883 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3884 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3885 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3886 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3887 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3888 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3889 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3890 mono_jit_code_hash_init (&info->interp_code_hash);
3892 domain->runtime_info = info;
3895 static void
3896 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3898 MonoJumpList *jlist = (MonoJumpList *)value;
3899 g_slist_free ((GSList*)jlist->list);
3902 static void
3903 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3905 GSList *list = (GSList *)value;
3906 g_slist_free (list);
3909 static void
3910 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3912 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3913 mono_code_manager_destroy (di->code_mp);
3914 g_free (di);
3917 static void
3918 runtime_invoke_info_free (gpointer value)
3920 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3922 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3923 if (info->dyn_call_info)
3924 mono_arch_dyn_call_free (info->dyn_call_info);
3925 #endif
3926 g_free (info);
3929 static void
3930 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3932 g_slist_free ((GSList*)value);
3935 static void
3936 mini_free_jit_domain_info (MonoDomain *domain)
3938 MonoJitDomainInfo *info = domain_jit_info (domain);
3940 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3941 g_hash_table_destroy (info->jump_target_hash);
3942 if (info->jump_target_got_slot_hash) {
3943 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3944 g_hash_table_destroy (info->jump_target_got_slot_hash);
3946 if (info->dynamic_code_hash) {
3947 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3948 g_hash_table_destroy (info->dynamic_code_hash);
3950 g_hash_table_destroy (info->method_code_hash);
3951 g_hash_table_destroy (info->jump_trampoline_hash);
3952 g_hash_table_destroy (info->jit_trampoline_hash);
3953 g_hash_table_destroy (info->delegate_trampoline_hash);
3954 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3955 g_hash_table_destroy (info->mrgctx_hash);
3956 g_hash_table_destroy (info->method_rgctx_hash);
3957 g_hash_table_destroy (info->interp_method_pointer_hash);
3958 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3959 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3960 g_hash_table_destroy (info->seq_points);
3961 g_hash_table_destroy (info->arch_seq_points);
3962 if (info->agent_info)
3963 mini_get_dbg_callbacks ()->free_domain_info (domain);
3964 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3965 if (info->llvm_jit_callees) {
3966 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3967 g_hash_table_destroy (info->llvm_jit_callees);
3969 mono_internal_hash_table_destroy (&info->interp_code_hash);
3970 #ifdef ENABLE_LLVM
3971 mono_llvm_free_domain_info (domain);
3972 #endif
3974 g_free (domain->runtime_info);
3975 domain->runtime_info = NULL;
3978 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3980 static void
3981 code_manager_chunk_new (void *chunk, int size)
3983 mono_arch_code_chunk_new (chunk, size);
3986 static void
3987 code_manager_chunk_destroy (void *chunk)
3989 mono_arch_code_chunk_destroy (chunk);
3992 #endif
3994 #ifdef ENABLE_LLVM
3995 static gboolean
3996 llvm_init_inner (void)
3998 if (!mono_llvm_load (NULL))
3999 return FALSE;
4001 mono_llvm_init ();
4002 return TRUE;
4004 #endif
4007 * mini_llvm_init:
4009 * Load and initialize LLVM support.
4010 * Return TRUE on success.
4012 gboolean
4013 mini_llvm_init (void)
4015 #ifdef ENABLE_LLVM
4016 static gboolean llvm_inited;
4017 static gboolean init_result;
4019 mono_loader_lock_if_inited ();
4020 if (!llvm_inited) {
4021 init_result = llvm_init_inner ();
4022 llvm_inited = TRUE;
4024 mono_loader_unlock_if_inited ();
4025 return init_result;
4026 #else
4027 return FALSE;
4028 #endif
4031 void
4032 mini_add_profiler_argument (const char *desc)
4034 if (!profile_options)
4035 profile_options = g_ptr_array_new ();
4037 g_ptr_array_add (profile_options, (gpointer) desc);
4041 static MonoEECallbacks interp_cbs = {0};
4043 void
4044 mini_install_interp_callbacks (MonoEECallbacks *cbs)
4046 memcpy (&interp_cbs, cbs, sizeof (MonoEECallbacks));
4049 MonoEECallbacks *
4050 mini_get_interp_callbacks (void)
4052 return &interp_cbs;
4055 static MonoDebuggerCallbacks dbg_cbs;
4057 void
4058 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4060 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4061 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4064 MonoDebuggerCallbacks*
4065 mini_get_dbg_callbacks (void)
4067 return &dbg_cbs;
4071 mono_ee_api_version (void)
4073 return MONO_EE_API_VERSION;
4076 void
4077 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4079 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4082 void
4083 mono_interp_to_native_trampoline (gpointer addr, gpointer ccontext)
4085 mini_get_interp_callbacks ()->to_native_trampoline (addr, ccontext);
4088 static gboolean
4089 mini_is_interpreter_enabled (void)
4091 return mono_use_interpreter;
4094 static const char*
4095 mono_get_runtime_build_version (void);
4097 MonoDomain *
4098 mini_init (const char *filename, const char *runtime_version)
4100 ERROR_DECL (error);
4101 MonoDomain *domain;
4102 MonoRuntimeCallbacks callbacks;
4103 MonoThreadInfoRuntimeCallbacks ticallbacks;
4104 MonoCodeManagerCallbacks code_manager_callbacks;
4106 MONO_VES_INIT_BEGIN ();
4108 CHECKED_MONO_INIT ();
4110 #if defined(__linux__)
4111 if (access ("/proc/self/maps", F_OK) != 0) {
4112 g_print ("Mono requires /proc to be mounted.\n");
4113 exit (1);
4115 #endif
4117 mono_interp_stub_init ();
4118 #ifndef DISABLE_INTERPRETER
4119 if (mono_use_interpreter)
4120 mono_ee_interp_init (mono_interp_opts_string);
4121 #endif
4123 mono_debugger_agent_stub_init ();
4124 #ifndef DISABLE_SDB
4125 mono_debugger_agent_init ();
4126 #endif
4128 if (sdb_options)
4129 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4131 mono_os_mutex_init_recursive (&jit_mutex);
4133 mono_cross_helpers_run ();
4135 mono_counters_init ();
4137 mini_jit_init ();
4139 mini_jit_init_job_control ();
4141 /* Happens when using the embedding interface */
4142 if (!default_opt_set)
4143 default_opt = mono_parse_default_optimizations (NULL);
4145 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4146 if (mono_aot_only)
4147 mono_set_generic_sharing_vt_supported (TRUE);
4148 #else
4149 if (mono_llvm_only)
4150 mono_set_generic_sharing_vt_supported (TRUE);
4151 #endif
4153 mono_tls_init_runtime_keys ();
4155 if (!global_codeman)
4156 global_codeman = mono_code_manager_new ();
4158 memset (&callbacks, 0, sizeof (callbacks));
4159 callbacks.create_ftnptr = mini_create_ftnptr;
4160 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4161 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4162 callbacks.get_runtime_build_version = mono_get_runtime_build_version;
4163 callbacks.set_cast_details = mono_set_cast_details;
4164 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4165 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4166 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4167 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4168 callbacks.imt_entry_inited = mini_imt_entry_inited;
4169 callbacks.init_delegate = mini_init_delegate;
4170 #define JIT_INVOKE_WORKS
4171 #ifdef JIT_INVOKE_WORKS
4172 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4173 #endif
4174 #define JIT_TRAMPOLINES_WORK
4175 #ifdef JIT_TRAMPOLINES_WORK
4176 callbacks.compile_method = mono_jit_compile_method;
4177 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4178 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4179 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4180 callbacks.free_method = mono_jit_free_method;
4181 #ifndef DISABLE_REMOTING
4182 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4183 #endif
4184 #endif
4185 #ifndef DISABLE_REMOTING
4186 if (mono_use_interpreter)
4187 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4188 #endif
4189 callbacks.is_interpreter_enabled = mini_is_interpreter_enabled;
4190 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4192 #ifndef DISABLE_CRASH_REPORTING
4193 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4194 #endif
4196 mono_install_callbacks (&callbacks);
4198 memset (&ticallbacks, 0, sizeof (ticallbacks));
4199 ticallbacks.setup_async_callback = mono_setup_async_callback;
4200 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
4201 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
4202 ticallbacks.thread_state_init = mono_thread_state_init;
4204 #ifndef HOST_WIN32
4205 mono_w32handle_init ();
4206 #endif
4208 mono_thread_info_runtime_init (&ticallbacks);
4210 if (g_hasenv ("MONO_DEBUG")) {
4211 mini_parse_debug_options ();
4214 mono_code_manager_init ();
4216 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
4217 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4218 code_manager_callbacks.chunk_new = code_manager_chunk_new;
4219 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
4220 #endif
4221 mono_code_manager_install_callbacks (&code_manager_callbacks);
4223 mono_hwcap_init ();
4225 mono_arch_cpu_init ();
4227 mono_arch_init ();
4229 mono_unwind_init ();
4231 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
4232 mono_lldb_init ("");
4233 mono_dont_free_domains = TRUE;
4236 #ifdef XDEBUG_ENABLED
4237 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4238 if (mono_xdebug) {
4239 mono_xdebug_init (mono_xdebug);
4240 g_free (mono_xdebug);
4241 /* So methods for multiple domains don't have the same address */
4242 mono_dont_free_domains = TRUE;
4243 mono_using_xdebug = TRUE;
4244 } else if (mini_get_debug_options ()->gdb) {
4245 mono_xdebug_init ((char*)"gdb");
4246 mono_dont_free_domains = TRUE;
4247 mono_using_xdebug = TRUE;
4249 #endif
4251 #ifdef ENABLE_LLVM
4252 if (mono_use_llvm) {
4253 if (!mono_llvm_load (NULL)) {
4254 mono_use_llvm = FALSE;
4255 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4258 if (mono_use_llvm)
4259 mono_llvm_init ();
4260 #endif
4262 mono_trampolines_init ();
4264 if (default_opt & MONO_OPT_AOT)
4265 mono_aot_init ();
4267 mini_get_dbg_callbacks ()->init ();
4269 #ifdef TARGET_WASM
4270 mono_wasm_debugger_init ();
4271 #endif
4273 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4274 mono_set_generic_sharing_supported (TRUE);
4275 #endif
4277 mono_thread_info_signals_init ();
4279 mono_init_native_crash_info ();
4281 #ifndef MONO_CROSS_COMPILE
4282 mono_runtime_install_handlers ();
4283 #endif
4284 mono_threads_install_cleanup (mini_thread_cleanup);
4286 #ifdef JIT_TRAMPOLINES_WORK
4287 mono_install_create_domain_hook (mini_create_jit_domain_info);
4288 mono_install_free_domain_hook (mini_free_jit_domain_info);
4289 #endif
4290 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4291 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4292 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4294 mono_profiler_state.context_enable = mini_profiler_context_enable;
4295 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4296 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4297 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4298 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4299 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4301 if (profile_options)
4302 for (guint i = 0; i < profile_options->len; i++)
4303 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4305 mono_profiler_started ();
4307 if (mini_debug_options.collect_pagefault_stats)
4308 mono_aot_set_make_unreadable (TRUE);
4310 if (runtime_version)
4311 domain = mono_init_version (filename, runtime_version);
4312 else
4313 domain = mono_init_from_assembly (filename, filename);
4315 if (mono_aot_only) {
4316 /* This helps catch code allocation requests */
4317 mono_code_manager_set_read_only (domain->code_mp);
4318 mono_marshal_use_aot_wrappers (TRUE);
4321 if (mono_llvm_only) {
4322 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline);
4323 mono_set_always_build_imt_trampolines (TRUE);
4324 } else if (mono_aot_only) {
4325 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4326 } else {
4327 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4330 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4331 mono_arch_finish_init ();
4333 /* This must come after mono_init () in the aot-only case */
4334 mono_exceptions_init ();
4336 /* This should come after mono_init () too */
4337 mini_gc_init ();
4339 mono_create_icall_signatures ();
4341 register_jit_stats ();
4343 #define JIT_CALLS_WORK
4344 #ifdef JIT_CALLS_WORK
4345 /* Needs to be called here since register_jit_icall depends on it */
4346 mono_marshal_init ();
4348 mono_arch_register_lowlevel_calls ();
4350 register_icalls ();
4352 mono_generic_sharing_init ();
4353 #endif
4355 #ifdef MONO_ARCH_SIMD_INTRINSICS
4356 mono_simd_intrinsics_init ();
4357 #endif
4359 mono_tasklets_init ();
4361 register_trampolines (domain);
4363 if (mono_compile_aot)
4365 * Avoid running managed code when AOT compiling, since the platform
4366 * might only support aot-only execution.
4368 mono_runtime_set_no_exec (TRUE);
4370 mono_mem_account_register_counters ();
4372 #define JIT_RUNTIME_WORKS
4373 #ifdef JIT_RUNTIME_WORKS
4374 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4375 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4376 mono_error_assert_ok (error);
4377 mono_thread_attach (domain);
4378 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4379 #endif
4381 if (mono_profiler_sampling_enabled ())
4382 mono_runtime_setup_stat_profiler ();
4384 MONO_PROFILER_RAISE (runtime_initialized, ());
4386 MONO_VES_INIT_END ();
4388 return domain;
4391 static void
4392 register_icalls (void)
4394 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4395 ves_icall_get_frame_info);
4396 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4397 ves_icall_get_trace);
4398 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4399 mono_runtime_install_handlers);
4400 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4401 mono_runtime_cleanup_handlers);
4403 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4404 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4405 mini_get_dbg_callbacks ()->unhandled_exception);
4406 #endif
4409 * It's important that we pass `TRUE` as the last argument here, as
4410 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4411 * *did* emit a wrapper, we'd be looking at infinite recursion since
4412 * the wrapper would call the icall which would call the wrapper and
4413 * so on.
4415 register_icall (mono_profiler_raise_method_enter, mono_icall_sig_void_ptr_ptr, TRUE);
4416 register_icall (mono_profiler_raise_method_leave, mono_icall_sig_void_ptr_ptr, TRUE);
4417 register_icall (mono_profiler_raise_method_tail_call, mono_icall_sig_void_ptr_ptr, TRUE);
4418 register_icall (mono_profiler_raise_exception_clause, mono_icall_sig_void_ptr_int_int_object, TRUE);
4420 register_icall (mono_trace_enter_method, mono_icall_sig_void_ptr_ptr, TRUE);
4421 register_icall (mono_trace_leave_method, mono_icall_sig_void_ptr_ptr, TRUE);
4422 g_assert (mono_get_lmf_addr == mono_tls_get_lmf_addr);
4423 register_icall (mono_jit_set_domain, mono_icall_sig_void_ptr, TRUE);
4424 register_icall (mono_domain_get, mono_icall_sig_ptr, TRUE);
4426 register_icall (mono_llvm_throw_exception, mono_icall_sig_void_object, TRUE);
4427 register_icall (mono_llvm_rethrow_exception, mono_icall_sig_void_object, TRUE);
4428 register_icall (mono_llvm_resume_exception, mono_icall_sig_void, TRUE);
4429 register_icall (mono_llvm_match_exception, mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
4430 register_icall (mono_llvm_clear_exception, NULL, TRUE);
4431 register_icall (mono_llvm_load_exception, mono_icall_sig_object, TRUE);
4432 register_icall (mono_llvm_throw_corlib_exception, mono_icall_sig_void_int, TRUE);
4433 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4434 register_icall (mono_llvm_set_unhandled_exception_handler, NULL, TRUE);
4436 // FIXME: This is broken
4437 #ifndef TARGET_WASM
4438 register_icall (mono_debug_personality, mono_icall_sig_int_int_int_ptr_ptr_ptr, TRUE);
4439 #endif
4440 #endif
4442 if (!mono_llvm_only) {
4443 register_dyn_icall (mono_get_throw_exception (), mono_arch_throw_exception, mono_icall_sig_void_object, TRUE);
4444 register_dyn_icall (mono_get_rethrow_exception (), mono_arch_rethrow_exception, mono_icall_sig_void_object, TRUE);
4445 register_dyn_icall (mono_get_throw_corlib_exception (), mono_arch_throw_corlib_exception, mono_icall_sig_void_ptr, TRUE);
4447 register_icall (mono_thread_get_undeniable_exception, mono_icall_sig_object, FALSE);
4448 register_icall (ves_icall_thread_finish_async_abort, mono_icall_sig_void, FALSE);
4449 register_icall (mono_thread_interruption_checkpoint, mono_icall_sig_object, FALSE);
4450 register_icall (mono_thread_force_interruption_checkpoint_noraise, mono_icall_sig_object, FALSE);
4452 register_icall (mono_threads_state_poll, mono_icall_sig_void, FALSE);
4454 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4455 register_opcode_emulation (OP_LMUL, __emul_lmul, mono_icall_sig_long_long_long, mono_llmult, FALSE);
4456 register_opcode_emulation (OP_LDIV, __emul_ldiv, mono_icall_sig_long_long_long, mono_lldiv, FALSE);
4457 register_opcode_emulation (OP_LDIV_UN, __emul_ldiv_un, mono_icall_sig_long_long_long, mono_lldiv_un, FALSE);
4458 register_opcode_emulation (OP_LREM, __emul_lrem, mono_icall_sig_long_long_long, mono_llrem, FALSE);
4459 register_opcode_emulation (OP_LREM_UN, __emul_lrem_un, mono_icall_sig_long_long_long, mono_llrem_un, FALSE);
4460 #endif
4461 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4462 register_opcode_emulation (OP_LMUL_OVF_UN, __emul_lmul_ovf_un, mono_icall_sig_long_long_long, mono_llmult_ovf_un, FALSE);
4463 register_opcode_emulation (OP_LMUL_OVF, __emul_lmul_ovf, mono_icall_sig_long_long_long, mono_llmult_ovf, FALSE);
4464 #endif
4466 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4467 register_opcode_emulation (OP_LSHL, __emul_lshl, mono_icall_sig_long_long_int32, mono_lshl, TRUE);
4468 register_opcode_emulation (OP_LSHR, __emul_lshr, mono_icall_sig_long_long_int32, mono_lshr, TRUE);
4469 register_opcode_emulation (OP_LSHR_UN, __emul_lshr_un, mono_icall_sig_long_long_int32, mono_lshr_un, TRUE);
4470 #endif
4472 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4473 register_opcode_emulation (OP_IDIV, __emul_op_idiv, mono_icall_sig_int32_int32_int32, mono_idiv, FALSE);
4474 register_opcode_emulation (OP_IDIV_UN, __emul_op_idiv_un, mono_icall_sig_int32_int32_int32, mono_idiv_un, FALSE);
4475 register_opcode_emulation (OP_IREM, __emul_op_irem, mono_icall_sig_int32_int32_int32, mono_irem, FALSE);
4476 register_opcode_emulation (OP_IREM_UN, __emul_op_irem_un, mono_icall_sig_int32_int32_int32, mono_irem_un, FALSE);
4477 #endif
4479 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4480 register_opcode_emulation (OP_IMUL, __emul_op_imul, mono_icall_sig_int32_int32_int32, mono_imul, TRUE);
4481 #endif
4483 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4484 register_opcode_emulation (OP_IMUL_OVF, __emul_op_imul_ovf, mono_icall_sig_int32_int32_int32, mono_imul_ovf, FALSE);
4485 register_opcode_emulation (OP_IMUL_OVF_UN, __emul_op_imul_ovf_un, mono_icall_sig_int32_int32_int32, mono_imul_ovf_un, FALSE);
4486 #endif
4488 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4489 register_opcode_emulation (OP_FDIV, __emul_fdiv, mono_icall_sig_double_double_double, mono_fdiv, FALSE);
4490 #endif
4492 register_opcode_emulation (OP_FCONV_TO_U8, __emul_fconv_to_u8, mono_icall_sig_ulong_double, mono_fconv_u8_2, FALSE);
4493 register_opcode_emulation (OP_RCONV_TO_U8, __emul_rconv_to_u8, mono_icall_sig_ulong_float, mono_rconv_u8, FALSE);
4494 register_opcode_emulation (OP_FCONV_TO_U4, __emul_fconv_to_u4, mono_icall_sig_uint32_double, mono_fconv_u4_2, FALSE);
4495 register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, FALSE);
4496 register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
4497 register_opcode_emulation (OP_RCONV_TO_OVF_I8, __emul_rconv_to_ovf_i8, mono_icall_sig_long_float, mono_rconv_ovf_i8, FALSE);
4498 register_opcode_emulation (OP_RCONV_TO_OVF_U8, __emul_rconv_to_ovf_u8, mono_icall_sig_ulong_float, mono_rconv_ovf_u8, FALSE);
4501 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4502 register_opcode_emulation (OP_FCONV_TO_I8, __emul_fconv_to_i8, mono_icall_sig_long_double, mono_fconv_i8, FALSE);
4503 register_opcode_emulation (OP_RCONV_TO_I8, __emul_rconv_to_i8, mono_icall_sig_long_float, mono_rconv_i8, FALSE);
4504 #endif
4506 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4507 register_opcode_emulation (OP_ICONV_TO_R_UN, __emul_iconv_to_r_un, mono_icall_sig_double_int32, mono_conv_to_r8_un, FALSE);
4508 #endif
4509 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4510 register_opcode_emulation (OP_LCONV_TO_R8, __emul_lconv_to_r8, mono_icall_sig_double_long, mono_lconv_to_r8, FALSE);
4511 #endif
4512 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4513 register_opcode_emulation (OP_LCONV_TO_R4, __emul_lconv_to_r4, mono_icall_sig_float_long, mono_lconv_to_r4, FALSE);
4514 #endif
4515 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4516 register_opcode_emulation (OP_LCONV_TO_R_UN, __emul_lconv_to_r8_un, mono_icall_sig_double_long, mono_lconv_to_r8_un, FALSE);
4517 #endif
4518 #ifdef MONO_ARCH_EMULATE_FREM
4519 register_opcode_emulation (OP_FREM, __emul_frem, mono_icall_sig_double_double_double, mono_fmod, FALSE);
4520 register_opcode_emulation (OP_RREM, __emul_rrem, mono_icall_sig_float_float_float, fmodf, FALSE);
4521 #endif
4523 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4524 if (mono_arch_is_soft_float ()) {
4525 register_opcode_emulation (OP_FSUB, __emul_fsub, mono_icall_sig_double_double_double, mono_fsub, FALSE);
4526 register_opcode_emulation (OP_FADD, __emul_fadd, mono_icall_sig_double_double_double, mono_fadd, FALSE);
4527 register_opcode_emulation (OP_FMUL, __emul_fmul, mono_icall_sig_double_double_double, mono_fmul, FALSE);
4528 register_opcode_emulation (OP_FNEG, __emul_fneg, mono_icall_sig_double_double, mono_fneg, FALSE);
4529 register_opcode_emulation (OP_ICONV_TO_R8, __emul_iconv_to_r8, mono_icall_sig_double_int32, mono_conv_to_r8, FALSE);
4530 register_opcode_emulation (OP_ICONV_TO_R4, __emul_iconv_to_r4, mono_icall_sig_double_int32, mono_conv_to_r4, FALSE);
4531 register_opcode_emulation (OP_FCONV_TO_R4, __emul_fconv_to_r4, mono_icall_sig_double_double, mono_fconv_r4, FALSE);
4532 register_opcode_emulation (OP_FCONV_TO_I1, __emul_fconv_to_i1, mono_icall_sig_int8_double, mono_fconv_i1, FALSE);
4533 register_opcode_emulation (OP_FCONV_TO_I2, __emul_fconv_to_i2, mono_icall_sig_int16_double, mono_fconv_i2, FALSE);
4534 register_opcode_emulation (OP_FCONV_TO_I4, __emul_fconv_to_i4, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4535 register_opcode_emulation (OP_FCONV_TO_U1, __emul_fconv_to_u1, mono_icall_sig_uint8_double, mono_fconv_u1, FALSE);
4536 register_opcode_emulation (OP_FCONV_TO_U2, __emul_fconv_to_u2, mono_icall_sig_uint16_double, mono_fconv_u2, FALSE);
4538 #if TARGET_SIZEOF_VOID_P == 4
4539 register_opcode_emulation (OP_FCONV_TO_I, __emul_fconv_to_i, mono_icall_sig_int32_double, mono_fconv_i4, FALSE);
4540 #endif
4542 register_opcode_emulation (OP_FBEQ, __emul_fcmp_eq, mono_icall_sig_uint32_double_double, mono_fcmp_eq, FALSE);
4543 register_opcode_emulation (OP_FBLT, __emul_fcmp_lt, mono_icall_sig_uint32_double_double, mono_fcmp_lt, FALSE);
4544 register_opcode_emulation (OP_FBGT, __emul_fcmp_gt, mono_icall_sig_uint32_double_double, mono_fcmp_gt, FALSE);
4545 register_opcode_emulation (OP_FBLE, __emul_fcmp_le, mono_icall_sig_uint32_double_double, mono_fcmp_le, FALSE);
4546 register_opcode_emulation (OP_FBGE, __emul_fcmp_ge, mono_icall_sig_uint32_double_double, mono_fcmp_ge, FALSE);
4547 register_opcode_emulation (OP_FBNE_UN, __emul_fcmp_ne_un, mono_icall_sig_uint32_double_double, mono_fcmp_ne_un, FALSE);
4548 register_opcode_emulation (OP_FBLT_UN, __emul_fcmp_lt_un, mono_icall_sig_uint32_double_double, mono_fcmp_lt_un, FALSE);
4549 register_opcode_emulation (OP_FBGT_UN, __emul_fcmp_gt_un, mono_icall_sig_uint32_double_double, mono_fcmp_gt_un, FALSE);
4550 register_opcode_emulation (OP_FBLE_UN, __emul_fcmp_le_un, mono_icall_sig_uint32_double_double, mono_fcmp_le_un, FALSE);
4551 register_opcode_emulation (OP_FBGE_UN, __emul_fcmp_ge_un, mono_icall_sig_uint32_double_double, mono_fcmp_ge_un, FALSE);
4553 register_opcode_emulation (OP_FCEQ, __emul_fcmp_ceq, mono_icall_sig_uint32_double_double, mono_fceq, FALSE);
4554 register_opcode_emulation (OP_FCGT, __emul_fcmp_cgt, mono_icall_sig_uint32_double_double, mono_fcgt, FALSE);
4555 register_opcode_emulation (OP_FCGT_UN, __emul_fcmp_cgt_un, mono_icall_sig_uint32_double_double, mono_fcgt_un, FALSE);
4556 register_opcode_emulation (OP_FCLT, __emul_fcmp_clt, mono_icall_sig_uint32_double_double, mono_fclt, FALSE);
4557 register_opcode_emulation (OP_FCLT_UN, __emul_fcmp_clt_un, mono_icall_sig_uint32_double_double, mono_fclt_un, FALSE);
4559 register_icall (mono_fload_r4, mono_icall_sig_double_ptr, FALSE);
4560 register_icall (mono_fstore_r4, mono_icall_sig_void_double_ptr, FALSE);
4561 register_icall (mono_fload_r4_arg, mono_icall_sig_uint32_double, FALSE);
4562 register_icall (mono_isfinite_double, mono_icall_sig_int32_double, FALSE);
4564 #endif
4565 register_icall (mono_ckfinite, mono_icall_sig_double_double, FALSE);
4567 #ifdef COMPRESSED_INTERFACE_BITMAP
4568 register_icall (mono_class_interface_match, mono_icall_sig_uint32_ptr_int32, TRUE);
4569 #endif
4571 // FIXME Elsewhere these are registered with no_wrapper = FALSE
4572 #if SIZEOF_REGISTER == 4
4573 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_uint32_double, mono_fconv_u4, TRUE);
4574 #else
4575 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_ulong_double, mono_fconv_u8, TRUE);
4576 #endif
4578 /* other jit icalls */
4579 register_icall (ves_icall_mono_delegate_ctor, mono_icall_sig_void_object_object_ptr, FALSE);
4580 register_icall (ves_icall_mono_delegate_ctor_interp, mono_icall_sig_void_object_object_ptr, FALSE);
4581 register_icall (mono_class_static_field_address,
4582 mono_icall_sig_ptr_ptr_ptr, FALSE);
4583 register_icall (mono_ldtoken_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4584 register_icall (mono_ldtoken_wrapper_generic_shared,
4585 mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4586 register_icall (mono_get_special_static_data, mono_icall_sig_ptr_int, FALSE);
4587 register_icall (ves_icall_mono_ldstr, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4588 register_icall (mono_helper_stelem_ref_check, mono_icall_sig_void_object_object, FALSE);
4589 register_icall (ves_icall_object_new, mono_icall_sig_object_ptr_ptr, FALSE);
4590 register_icall (ves_icall_object_new_specific, mono_icall_sig_object_ptr, FALSE);
4591 register_icall (ves_icall_array_new, mono_icall_sig_object_ptr_ptr_int32, FALSE);
4592 register_icall (ves_icall_array_new_specific, mono_icall_sig_object_ptr_int32, FALSE);
4593 register_icall (ves_icall_runtime_class_init, mono_icall_sig_void_ptr, FALSE);
4594 register_icall (mono_ldftn, mono_icall_sig_ptr_ptr, FALSE);
4595 register_icall (mono_ldvirtfn, mono_icall_sig_ptr_object_ptr, FALSE);
4596 register_icall (mono_ldvirtfn_gshared, mono_icall_sig_ptr_object_ptr, FALSE);
4597 register_icall (mono_helper_compile_generic_method, mono_icall_sig_ptr_object_ptr_ptr, FALSE);
4598 register_icall (mono_helper_ldstr, mono_icall_sig_object_ptr_int, FALSE);
4599 register_icall (mono_helper_ldstr_mscorlib, mono_icall_sig_object_int, FALSE);
4600 register_icall (mono_helper_newobj_mscorlib, mono_icall_sig_object_int, FALSE);
4601 register_icall (mono_value_copy_internal, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
4602 register_icall (mono_object_castclass_unbox, mono_icall_sig_object_object_ptr, FALSE);
4603 register_icall (mono_break, NULL, TRUE);
4604 register_icall (mono_create_corlib_exception_0, mono_icall_sig_object_int, TRUE);
4605 register_icall (mono_create_corlib_exception_1, mono_icall_sig_object_int_object, TRUE);
4606 register_icall (mono_create_corlib_exception_2, mono_icall_sig_object_int_object_object, TRUE);
4607 register_icall (mono_array_new_1, mono_icall_sig_object_ptr_int, FALSE);
4608 register_icall (mono_array_new_2, mono_icall_sig_object_ptr_int_int, FALSE);
4609 register_icall (mono_array_new_3, mono_icall_sig_object_ptr_int_int_int, FALSE);
4610 register_icall (mono_array_new_4, mono_icall_sig_object_ptr_int_int_int_int, FALSE);
4611 register_icall (mono_array_new_n_icall, mono_icall_sig_object_ptr_int_ptr, FALSE);
4612 register_icall (mono_get_native_calli_wrapper, mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4613 register_icall (mono_resume_unwind, mono_icall_sig_void_ptr, TRUE);
4614 register_icall (mono_gsharedvt_constrained_call, mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr, FALSE);
4615 register_icall (mono_gsharedvt_value_copy, mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4617 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4618 MonoRangeCopyFunction const mono_gc_wbarrier_range_copy = mono_gc_get_range_copy_func ();
4619 register_icall_no_wrapper (mono_gc_wbarrier_range_copy, mono_icall_sig_void_ptr_ptr_int);
4621 register_icall (mono_object_castclass_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4622 register_icall (mono_object_isinst_with_cache, mono_icall_sig_object_object_ptr_ptr, FALSE);
4623 register_icall (mono_generic_class_init, mono_icall_sig_void_ptr, FALSE);
4624 register_icall (mono_fill_class_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4625 register_icall (mono_fill_method_rgctx, mono_icall_sig_ptr_ptr_int, FALSE);
4627 register_dyn_icall (mini_get_dbg_callbacks ()->user_break, mono_debugger_agent_user_break, mono_icall_sig_void, FALSE);
4629 register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_int, TRUE);
4630 register_icall (mini_llvm_init_gshared_method_this, mono_icall_sig_void_ptr_int_object, TRUE);
4631 register_icall (mini_llvm_init_gshared_method_mrgctx, mono_icall_sig_void_ptr_int_ptr, TRUE);
4632 register_icall (mini_llvm_init_gshared_method_vtable, mono_icall_sig_void_ptr_int_ptr, TRUE);
4634 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4635 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr);
4636 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call, mono_icall_sig_ptr_ptr_int_ptr);
4637 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call, mono_icall_sig_ptr_ptr_int_ptr);
4638 /* This needs a wrapper so it can have a preserveall cconv */
4639 register_icall (mini_llvmonly_init_vtable_slot, mono_icall_sig_ptr_ptr_int, FALSE);
4640 register_icall (mini_llvmonly_init_delegate, mono_icall_sig_void_object, TRUE);
4641 register_icall (mini_llvmonly_init_delegate_virtual, mono_icall_sig_void_object_object_ptr, TRUE);
4642 register_icall (mini_llvmonly_throw_nullref_exception, mono_icall_sig_void, TRUE);
4644 register_icall (mono_get_assembly_object, mono_icall_sig_object_ptr, TRUE);
4645 register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE);
4646 register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE);
4647 register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void);
4649 register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);
4650 register_icall_with_wrapper (mono_monitor_enter_v4_internal, mono_icall_sig_void_obj_ptr);
4651 register_icall_no_wrapper (mono_monitor_enter_fast, mono_icall_sig_int_obj);
4652 register_icall_no_wrapper (mono_monitor_enter_v4_fast, mono_icall_sig_int_obj_ptr);
4654 #ifdef TARGET_IOS
4655 register_icall (pthread_getspecific, mono_icall_sig_ptr_ptr, TRUE);
4656 #endif
4657 /* Register tls icalls */
4658 register_icall_no_wrapper (mono_tls_get_thread, mono_icall_sig_ptr);
4659 register_icall_no_wrapper (mono_tls_get_jit_tls, mono_icall_sig_ptr);
4660 register_icall_no_wrapper (mono_tls_get_domain, mono_icall_sig_ptr);
4661 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, mono_icall_sig_ptr);
4662 register_icall_no_wrapper (mono_tls_get_lmf_addr, mono_icall_sig_ptr);
4663 register_icall_no_wrapper (mono_tls_set_thread, mono_icall_sig_void_ptr);
4664 register_icall_no_wrapper (mono_tls_set_jit_tls, mono_icall_sig_void_ptr);
4665 register_icall_no_wrapper (mono_tls_set_domain, mono_icall_sig_void_ptr);
4666 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, mono_icall_sig_void_ptr);
4667 register_icall_no_wrapper (mono_tls_set_lmf_addr, mono_icall_sig_void_ptr);
4669 register_icall_no_wrapper (mono_interp_entry_from_trampoline, mono_icall_sig_void_ptr_ptr);
4670 register_icall_no_wrapper (mono_interp_to_native_trampoline, mono_icall_sig_void_ptr_ptr);
4672 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4673 mono_arch_register_icall ();
4674 #endif
4677 MonoJitStats mono_jit_stats = {0};
4680 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4681 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4683 MONO_NO_SANITIZE_THREAD
4684 static void
4685 print_jit_stats (void)
4687 if (mono_jit_stats.enabled) {
4688 g_print ("Mono Jit statistics\n");
4689 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4690 mono_jit_stats.max_ratio_method);
4691 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4692 mono_jit_stats.biggest_method);
4694 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4695 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4696 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4697 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4698 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4699 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4700 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4701 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4703 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4704 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4705 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4707 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4708 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4709 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4710 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4712 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4713 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4714 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4715 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4716 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4717 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4718 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4719 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4721 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4722 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4723 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4725 g_free (mono_jit_stats.max_ratio_method);
4726 mono_jit_stats.max_ratio_method = NULL;
4727 g_free (mono_jit_stats.biggest_method);
4728 mono_jit_stats.biggest_method = NULL;
4732 #ifdef DISABLE_CLEANUP
4733 void
4734 mini_cleanup (MonoDomain *domain)
4737 #else
4738 void
4739 mini_cleanup (MonoDomain *domain)
4741 if (mono_profiler_sampling_enabled ())
4742 mono_runtime_shutdown_stat_profiler ();
4744 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4746 #ifndef DISABLE_COM
4747 mono_cominterop_release_all_rcws ();
4748 #endif
4750 #ifndef MONO_CROSS_COMPILE
4752 * mono_domain_finalize () needs to be called early since it needs the
4753 * execution engine still fully working (it may invoke managed finalizers).
4755 mono_domain_finalize (domain, 2000);
4756 #endif
4758 /* This accesses metadata so needs to be called before runtime shutdown */
4759 print_jit_stats ();
4761 #ifndef MONO_CROSS_COMPILE
4762 mono_runtime_cleanup (domain);
4763 #endif
4765 mono_threadpool_cleanup ();
4767 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4769 mono_profiler_cleanup ();
4771 if (profile_options)
4772 g_ptr_array_free (profile_options, TRUE);
4774 free_jit_tls_data (mono_tls_get_jit_tls ());
4776 mono_icall_cleanup ();
4778 mono_runtime_cleanup_handlers ();
4780 #ifndef MONO_CROSS_COMPILE
4781 mono_domain_free (domain, TRUE);
4782 #endif
4784 #ifdef ENABLE_LLVM
4785 if (mono_use_llvm)
4786 mono_llvm_cleanup ();
4787 #endif
4789 mono_aot_cleanup ();
4791 mono_trampolines_cleanup ();
4793 mono_unwind_cleanup ();
4795 mono_code_manager_destroy (global_codeman);
4796 g_free (vtable_trampolines);
4798 mini_jit_cleanup ();
4800 mono_tramp_info_cleanup ();
4802 mono_arch_cleanup ();
4804 mono_generic_sharing_cleanup ();
4806 mono_cleanup_native_crash_info ();
4808 mono_cleanup ();
4810 mono_trace_cleanup ();
4812 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4814 if (mono_inject_async_exc_method)
4815 mono_method_desc_free (mono_inject_async_exc_method);
4817 mono_tls_free_keys ();
4819 mono_os_mutex_destroy (&jit_mutex);
4821 mono_code_manager_cleanup ();
4823 #ifndef HOST_WIN32
4824 mono_w32handle_cleanup ();
4825 #endif
4827 #endif
4829 void
4830 mono_set_defaults (int verbose_level, guint32 opts)
4832 mini_verbose = verbose_level;
4833 mono_set_optimizations (opts);
4836 void
4837 mono_disable_optimizations (guint32 opts)
4839 default_opt &= ~opts;
4842 void
4843 mono_set_optimizations (guint32 opts)
4845 default_opt = opts;
4846 default_opt_set = TRUE;
4847 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4848 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4849 #else
4850 if (mono_llvm_only)
4851 mono_set_generic_sharing_vt_supported (TRUE);
4852 #endif
4855 void
4856 mono_set_verbose_level (guint32 level)
4858 mini_verbose = level;
4861 static const char*
4862 mono_get_runtime_build_version (void)
4864 return FULL_VERSION;
4868 * mono_get_runtime_build_info:
4869 * The returned string is owned by the caller. The returned string
4870 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4871 * \returns the runtime version + build date in string format.
4873 char*
4874 mono_get_runtime_build_info (void)
4876 if (mono_build_date)
4877 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4878 else
4879 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4882 static void
4883 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4885 GHashTable *assemblies = (GHashTable*)user_data;
4886 MonoImage *image = mono_assembly_get_image_internal (ass);
4887 MonoMethod *method, *invoke;
4888 int i, count = 0;
4890 if (g_hash_table_lookup (assemblies, ass))
4891 return;
4893 g_hash_table_insert (assemblies, ass, ass);
4895 if (mini_verbose > 0)
4896 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4898 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4899 ERROR_DECL (error);
4901 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
4902 if (!method) {
4903 mono_error_cleanup (error); /* FIXME don't swallow the error */
4904 continue;
4906 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4907 continue;
4908 if (method->is_generic || mono_class_is_gtd (method->klass))
4909 continue;
4911 count++;
4912 if (mini_verbose > 1) {
4913 char * desc = mono_method_full_name (method, TRUE);
4914 g_print ("Compiling %d %s\n", count, desc);
4915 g_free (desc);
4917 mono_compile_method_checked (method, error);
4918 if (!is_ok (error)) {
4919 mono_error_cleanup (error); /* FIXME don't swallow the error */
4920 continue;
4922 if (strcmp (method->name, "Finalize") == 0) {
4923 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4924 mono_compile_method_checked (invoke, error);
4925 mono_error_assert_ok (error);
4927 #ifndef DISABLE_REMOTING
4928 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
4929 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
4930 mono_error_assert_ok (error);
4931 mono_compile_method_checked (invoke, error);
4932 mono_error_assert_ok (error);
4934 #endif
4937 /* Load and precompile referenced assemblies as well */
4938 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4939 mono_assembly_load_reference (image, i);
4940 if (image->references [i])
4941 mono_precompile_assembly (image->references [i], assemblies);
4945 void mono_precompile_assemblies ()
4947 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4949 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4951 g_hash_table_destroy (assemblies);
4955 * Used by LLVM.
4956 * Have to export this for AOT.
4958 void
4959 mono_personality (void)
4961 /* Not used */
4962 g_assert_not_reached ();
4965 static MonoBreakPolicy
4966 always_insert_breakpoint (MonoMethod *method)
4968 return MONO_BREAK_POLICY_ALWAYS;
4971 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4974 * mono_set_break_policy:
4975 * \param policy_callback the new callback function
4977 * Allow embedders to decide whether to actually obey breakpoint instructions
4978 * (both break IL instructions and \c Debugger.Break method calls), for example
4979 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4980 * untrusted or semi-trusted code.
4982 * \p policy_callback will be called every time a break point instruction needs to
4983 * be inserted with the method argument being the method that calls \c Debugger.Break
4984 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4985 * if it wants the breakpoint to not be effective in the given method.
4986 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4988 void
4989 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4991 if (policy_callback)
4992 break_policy_func = policy_callback;
4993 else
4994 break_policy_func = always_insert_breakpoint;
4997 gboolean
4998 mini_should_insert_breakpoint (MonoMethod *method)
5000 switch (break_policy_func (method)) {
5001 case MONO_BREAK_POLICY_ALWAYS:
5002 return TRUE;
5003 case MONO_BREAK_POLICY_NEVER:
5004 return FALSE;
5005 case MONO_BREAK_POLICY_ON_DBG:
5006 g_warning ("mdb no longer supported");
5007 return FALSE;
5008 default:
5009 g_warning ("Incorrect value returned from break policy callback");
5010 return FALSE;
5014 // Custom handlers currently only implemented by Windows.
5015 #ifndef HOST_WIN32
5016 gboolean
5017 mono_runtime_install_custom_handlers (const char *handlers)
5019 return FALSE;
5022 void
5023 mono_runtime_install_custom_handlers_usage (void)
5025 fprintf (stdout,
5026 "Custom Handlers:\n"
5027 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5028 " separated list of available handlers to install.\n"
5029 "\n"
5030 "No handlers supported on current platform.\n");
5032 #endif /* HOST_WIN32 */