[jit] Constant folding for some Math operations on doubles (#9281)
[mono-project.git] / mono / mini / mini-runtime.c
blob04a2c3763e3980ddc4fea0b6f752694cd14fecb8
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/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/metadata/icall-internals.h>
55 #define MONO_MATH_DECLARE_ALL 1
56 #include <mono/utils/mono-math.h>
57 #include <mono/utils/mono-compiler.h>
58 #include <mono/utils/mono-counters.h>
59 #include <mono/utils/mono-error-internals.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-mmap.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-tls.h>
64 #include <mono/utils/mono-hwcap.h>
65 #include <mono/utils/dtrace.h>
66 #include <mono/utils/mono-signal-handler.h>
67 #include <mono/utils/mono-threads.h>
68 #include <mono/utils/mono-threads-coop.h>
69 #include <mono/utils/checked-build.h>
70 #include <mono/utils/mono-compiler.h>
71 #include <mono/utils/mono-proclib.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/threadpool.h>
75 #include "mini.h"
76 #include "seq-points.h"
77 #include "tasklets.h"
78 #include <string.h>
79 #include <ctype.h>
80 #include "trace.h"
81 #include "version.h"
82 #include "aot-compiler.h"
83 #include "aot-runtime.h"
84 #include "llvmonly-runtime.h"
86 #include "jit-icalls.h"
88 #include "mini-gc.h"
89 #include "mini-llvm.h"
90 #include "debugger-agent.h"
91 #include "lldb.h"
92 #include "mini-runtime.h"
93 #include "interp/interp.h"
95 #ifdef MONO_ARCH_LLVM_SUPPORTED
96 #ifdef ENABLE_LLVM
97 #include "mini-llvm-cpp.h"
98 #include "llvm-jit.h"
99 #endif
100 #endif
102 static guint32 default_opt = 0;
103 static gboolean default_opt_set = FALSE;
105 gboolean mono_compile_aot = FALSE;
106 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
107 gboolean mono_aot_only = FALSE;
108 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
109 gboolean mono_llvm_only = FALSE;
110 /* By default, don't require AOT but attempt to probe */
111 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NORMAL;
112 MonoEEFeatures mono_ee_features;
114 const char *mono_build_date;
115 gboolean mono_do_signal_chaining;
116 gboolean mono_do_crash_chaining;
117 int mini_verbose = 0;
120 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
121 * it can load AOT code compiled by LLVM.
123 gboolean mono_use_llvm = FALSE;
125 gboolean mono_use_interpreter = FALSE;
126 const char *mono_interp_opts_string = NULL;
128 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
129 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
130 static mono_mutex_t jit_mutex;
132 static MonoCodeManager *global_codeman;
134 MonoDebugOptions mini_debug_options;
135 char *sdb_options;
137 #ifdef VALGRIND_JIT_REGISTER_MAP
138 int valgrind_register;
139 #endif
140 GList* mono_aot_paths;
142 static GPtrArray *profile_options;
144 static GSList *tramp_infos;
145 GSList *mono_interp_only_classes;
147 static void register_icalls (void);
149 gboolean
150 mono_running_on_valgrind (void)
152 #ifndef HOST_WIN32
153 if (RUNNING_ON_VALGRIND){
154 #ifdef VALGRIND_JIT_REGISTER_MAP
155 valgrind_register = TRUE;
156 #endif
157 return TRUE;
158 } else
159 #endif
160 return FALSE;
163 typedef struct {
164 void *ip;
165 MonoMethod *method;
166 } FindTrampUserData;
168 static void
169 find_tramp (gpointer key, gpointer value, gpointer user_data)
171 FindTrampUserData *ud = (FindTrampUserData*)user_data;
173 if (value == ud->ip)
174 ud->method = (MonoMethod*)key;
177 /* debug function */
178 char*
179 mono_get_method_from_ip (void *ip)
181 MonoJitInfo *ji;
182 MonoMethod *method;
183 char *method_name;
184 char *res;
185 MonoDomain *domain = mono_domain_get ();
186 MonoDebugSourceLocation *location;
187 FindTrampUserData user_data;
189 if (!domain)
190 domain = mono_get_root_domain ();
192 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
193 if (!ji) {
194 user_data.ip = ip;
195 user_data.method = NULL;
196 mono_domain_lock (domain);
197 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
198 mono_domain_unlock (domain);
199 if (user_data.method) {
200 char *mname = mono_method_full_name (user_data.method, TRUE);
201 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
202 g_free (mname);
203 return res;
205 else
206 return NULL;
207 } else if (ji->is_trampoline) {
208 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
209 return res;
212 method = jinfo_get_method (ji);
213 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
214 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
216 char *file_loc = NULL;
217 if (location)
218 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
220 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);
222 mono_debug_free_source_location (location);
223 g_free (method_name);
224 g_free (file_loc);
226 return res;
230 * mono_pmip:
231 * \param ip an instruction pointer address
233 * This method is used from a debugger to get the name of the
234 * method at address \p ip. This routine is typically invoked from
235 * a debugger like this:
237 * (gdb) print mono_pmip ($pc)
239 * \returns the name of the method at address \p ip.
241 G_GNUC_UNUSED char *
242 mono_pmip (void *ip)
244 return mono_get_method_from_ip (ip);
248 * mono_print_method_from_ip:
249 * \param ip an instruction pointer address
251 * This method is used from a debugger to get the name of the
252 * method at address \p ip.
254 * This prints the name of the method at address \p ip in the standard
255 * output. Unlike \c mono_pmip which returns a string, this routine
256 * prints the value on the standard output.
258 MONO_ATTR_USED void
259 mono_print_method_from_ip (void *ip)
261 MonoJitInfo *ji;
262 char *method;
263 MonoDebugSourceLocation *source;
264 MonoDomain *domain = mono_domain_get ();
265 MonoDomain *target_domain = mono_domain_get ();
266 FindTrampUserData user_data;
267 MonoGenericSharingContext*gsctx;
268 const char *shared_type;
270 if (!domain)
271 domain = mono_get_root_domain ();
272 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
273 if (ji && ji->is_trampoline) {
274 MonoTrampInfo *tinfo = ji->d.tramp_info;
276 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
277 return;
280 if (!ji) {
281 user_data.ip = ip;
282 user_data.method = NULL;
283 mono_domain_lock (domain);
284 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
285 mono_domain_unlock (domain);
287 if (user_data.method) {
288 char *mname = mono_method_full_name (user_data.method, TRUE);
289 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
290 g_free (mname);
291 return;
294 g_print ("No method at %p\n", ip);
295 fflush (stdout);
296 return;
298 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
299 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
301 gsctx = mono_jit_info_get_generic_sharing_context (ji);
302 shared_type = "";
303 if (gsctx) {
304 if (gsctx->is_gsharedvt)
305 shared_type = "gsharedvt ";
306 else
307 shared_type = "gshared ";
310 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);
312 if (source)
313 g_print ("%s:%d\n", source->source_file, source->row);
314 fflush (stdout);
316 mono_debug_free_source_location (source);
317 g_free (method);
321 * mono_method_same_domain:
323 * Determine whenever two compiled methods are in the same domain, thus
324 * the address of the callee can be embedded in the caller.
326 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
328 MonoMethod *cmethod;
330 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
331 return FALSE;
334 * If the call was made from domain-neutral to domain-specific
335 * code, we can't patch the call site.
337 if (caller->domain_neutral && !callee->domain_neutral)
338 return FALSE;
340 cmethod = jinfo_get_method (caller);
341 if ((cmethod->klass == mono_defaults.appdomain_class) &&
342 (strstr (cmethod->name, "InvokeInDomain"))) {
343 /* The InvokeInDomain methods change the current appdomain */
344 return FALSE;
347 return TRUE;
351 * mono_global_codeman_reserve:
353 * Allocate code memory from the global code manager.
355 void *(mono_global_codeman_reserve) (int size)
357 void *ptr;
359 if (mono_aot_only)
360 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
362 if (!global_codeman) {
363 /* This can happen during startup */
364 global_codeman = mono_code_manager_new ();
365 return mono_code_manager_reserve (global_codeman, size);
367 else {
368 mono_jit_lock ();
369 ptr = mono_code_manager_reserve (global_codeman, size);
370 mono_jit_unlock ();
371 return ptr;
375 /* The callback shouldn't take any locks */
376 void
377 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
379 mono_jit_lock ();
380 mono_code_manager_foreach (global_codeman, func, user_data);
381 mono_jit_unlock ();
385 * mono_create_unwind_op:
387 * Create an unwind op with the given parameters.
389 MonoUnwindOp*
390 mono_create_unwind_op (int when, int tag, int reg, int val)
392 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
394 op->op = tag;
395 op->reg = reg;
396 op->val = val;
397 op->when = when;
399 return op;
402 MonoJumpInfoToken *
403 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
405 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
406 res->image = image;
407 res->token = token;
408 res->has_context = context != NULL;
409 if (context)
410 memcpy (&res->context, context, sizeof (MonoGenericContext));
412 return res;
415 MonoJumpInfoToken *
416 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
418 return mono_jump_info_token_new2 (mp, image, token, NULL);
422 * mono_tramp_info_create:
424 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
425 * of JI, and UNWIND_OPS.
427 MonoTrampInfo*
428 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
430 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
432 info->name = g_strdup (name);
433 info->code = code;
434 info->code_size = code_size;
435 info->ji = ji;
436 info->unwind_ops = unwind_ops;
438 return info;
441 void
442 mono_tramp_info_free (MonoTrampInfo *info)
444 g_free (info->name);
446 // FIXME: ji
447 mono_free_unwind_info (info->unwind_ops);
448 if (info->owns_uw_info)
449 g_free (info->uw_info);
450 g_free (info);
453 static void
454 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
456 MonoJitInfo *ji;
458 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
459 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
460 ji->d.tramp_info = info;
461 ji->is_trampoline = TRUE;
463 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
465 mono_jit_info_table_add (domain, ji);
469 * mono_tramp_info_register:
471 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
472 * INFO can be NULL.
473 * Frees INFO.
475 static void
476 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
478 MonoTrampInfo *copy;
480 if (!info)
481 return;
483 if (!domain)
484 domain = mono_get_root_domain ();
486 if (domain)
487 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
488 else
489 copy = g_new0 (MonoTrampInfo, 1);
491 copy->code = info->code;
492 copy->code_size = info->code_size;
493 copy->name = g_strdup (info->name);
495 if (info->unwind_ops) {
496 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
497 copy->owns_uw_info = TRUE;
498 if (domain) {
499 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
500 guint8 *temp = copy->uw_info;
501 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
502 memcpy (copy->uw_info, temp, copy->uw_info_len);
503 g_free (temp);
505 } else {
506 /* Trampolines from aot have the unwind ops already encoded */
507 copy->uw_info = info->uw_info;
508 copy->uw_info_len = info->uw_info_len;
511 mono_save_trampoline_xdebug_info (info);
512 mono_lldb_save_trampoline_info (info);
514 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
515 if (!aot)
516 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
517 #endif
519 if (!domain) {
520 /* If no root domain has been created yet, postpone the registration. */
521 mono_jit_lock ();
522 tramp_infos = g_slist_prepend (tramp_infos, copy);
523 mono_jit_unlock ();
524 } else if (copy->uw_info) {
525 /* Only register trampolines that have unwind infos */
526 register_trampoline_jit_info (domain, copy);
529 if (mono_jit_map_is_enabled ())
530 mono_emit_jit_tramp (info->code, info->code_size, info->name);
532 mono_tramp_info_free (info);
535 void
536 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
538 mono_tramp_info_register_internal (info, domain, FALSE);
541 void
542 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
544 mono_tramp_info_register_internal (info, domain, TRUE);
547 static void
548 mono_tramp_info_cleanup (void)
550 GSList *l;
552 for (l = tramp_infos; l; l = l->next) {
553 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
555 mono_tramp_info_free (info);
557 g_slist_free (tramp_infos);
560 /* Register trampolines created before the root domain was created in the jit info tables */
561 static void
562 register_trampolines (MonoDomain *domain)
564 GSList *l;
566 for (l = tramp_infos; l; l = l->next) {
567 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
569 register_trampoline_jit_info (domain, info);
573 G_GNUC_UNUSED static void
574 break_count (void)
579 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
580 * Set a breakpoint in break_count () to break the last time <x> is done.
582 G_GNUC_UNUSED gboolean
583 mono_debug_count (void)
585 static int count = 0, int_val = 0;
586 static gboolean inited, has_value = FALSE;
588 count ++;
590 if (!inited) {
591 char *value = g_getenv ("COUNT");
592 if (value) {
593 int_val = atoi (value);
594 g_free (value);
595 has_value = TRUE;
597 inited = TRUE;
600 if (!has_value)
601 return TRUE;
603 if (count == int_val)
604 break_count ();
606 if (count > int_val)
607 return FALSE;
609 return TRUE;
612 MonoMethod*
613 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
615 MonoMethod *wrapper;
616 gboolean check_exc = TRUE;
617 char *name;
619 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
620 /* This icall is used to check for exceptions, so don't check in the wrapper */
621 check_exc = FALSE;
623 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
624 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
625 g_free (name);
627 return wrapper;
630 gconstpointer
631 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
633 ERROR_DECL (error);
634 MonoMethod *wrapper;
635 gconstpointer trampoline;
636 MonoDomain *domain = mono_get_root_domain ();
638 if (callinfo->wrapper)
639 return callinfo->wrapper;
641 if (callinfo->trampoline)
642 return callinfo->trampoline;
644 wrapper = mono_icall_get_wrapper_method (callinfo);
646 if (do_compile) {
647 trampoline = mono_compile_method_checked (wrapper, error);
648 mono_error_assert_ok (error);
649 } else {
650 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
651 mono_error_assert_ok (error);
652 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
655 mono_loader_lock ();
656 if (!callinfo->trampoline) {
657 mono_register_jit_icall_wrapper (callinfo, trampoline);
658 callinfo->trampoline = trampoline;
660 mono_loader_unlock ();
662 return callinfo->trampoline;
665 gconstpointer
666 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
668 return mono_icall_get_wrapper_full (callinfo, FALSE);
671 static MonoJitDynamicMethodInfo*
672 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
674 MonoJitDynamicMethodInfo *res;
676 if (domain_jit_info (domain)->dynamic_code_hash)
677 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
678 else
679 res = NULL;
680 return res;
683 #ifdef __cplusplus
684 template <typename T>
685 static void
686 register_opcode_emulation (int opcode, const char *name, const char *sigstr, T func, const char *symbol, gboolean no_wrapper)
687 #else
688 static void
689 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_wrapper)
690 #endif
692 #ifndef DISABLE_JIT
693 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_wrapper);
694 #else
695 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
697 g_assert (!sig->hasthis);
698 g_assert (sig->param_count < 3);
700 mono_register_jit_icall_full (func, name, sig, no_wrapper, symbol);
701 #endif
705 * For JIT icalls implemented in C.
706 * NAME should be the same as the name of the C function whose address is FUNC.
707 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
708 * can't throw exceptions.
710 #ifdef __cplusplus
711 template <typename T>
712 static void
713 register_icall (T func, const char *name, const char *sigstr, gboolean avoid_wrapper)
714 #else
715 static void
716 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
717 #endif
719 MonoMethodSignature *sig;
721 if (sigstr)
722 sig = mono_create_icall_signature (sigstr);
723 else
724 sig = NULL;
726 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, name);
729 #ifdef __cplusplus
730 template <typename T>
731 static void
732 register_icall_no_wrapper (T func, const char *name, const char *sigstr)
733 #else
734 static void
735 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
736 #endif
738 MonoMethodSignature *sig;
740 if (sigstr)
741 sig = mono_create_icall_signature (sigstr);
742 else
743 sig = NULL;
745 mono_register_jit_icall_full (func, name, sig, TRUE, name);
748 #ifdef __cplusplus
749 template <typename T>
750 static void
751 register_icall_with_wrapper (T func, const char *name, const char *sigstr)
752 #else
753 static void
754 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
755 #endif
757 MonoMethodSignature *sig;
759 if (sigstr)
760 sig = mono_create_icall_signature (sigstr);
761 else
762 sig = NULL;
764 mono_register_jit_icall_full (func, name, sig, FALSE, name);
768 * Register an icall where FUNC is dynamically generated or otherwise not
769 * possible to link to it using NAME during AOT.
771 #ifdef __cplusplus
772 template <typename T>
773 static void
774 register_dyn_icall (T func, const char *name, const char *sigstr, gboolean save)
775 #else
776 static void
777 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
778 #endif
780 MonoMethodSignature *sig;
782 if (sigstr)
783 sig = mono_create_icall_signature (sigstr);
784 else
785 sig = NULL;
787 mono_register_jit_icall (func, name, sig, save);
790 MonoLMF *
791 mono_get_lmf (void)
793 MonoJitTlsData *jit_tls;
795 if ((jit_tls = mono_tls_get_jit_tls ()))
796 return jit_tls->lmf;
798 * We do not assert here because this function can be called from
799 * mini-gc.c on a thread that has not executed any managed code, yet
800 * (the thread object allocation can trigger a collection).
802 return NULL;
805 void
806 mono_set_lmf (MonoLMF *lmf)
808 (*mono_get_lmf_addr ()) = lmf;
811 static void
812 mono_set_jit_tls (MonoJitTlsData *jit_tls)
814 MonoThreadInfo *info;
816 mono_tls_set_jit_tls (jit_tls);
818 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
819 info = mono_thread_info_current ();
820 if (info)
821 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
824 static void
825 mono_set_lmf_addr (MonoLMF **lmf_addr)
827 MonoThreadInfo *info;
829 mono_tls_set_lmf_addr (lmf_addr);
831 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
832 info = mono_thread_info_current ();
833 if (info)
834 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
838 * mono_push_lmf:
840 * Push an MonoLMFExt frame on the LMF stack.
842 void
843 mono_push_lmf (MonoLMFExt *ext)
845 MonoLMF **lmf_addr;
847 lmf_addr = mono_get_lmf_addr ();
849 ext->lmf.previous_lmf = *lmf_addr;
850 /* Mark that this is a MonoLMFExt */
851 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
853 mono_set_lmf ((MonoLMF*)ext);
857 * mono_pop_lmf:
859 * Pop the last frame from the LMF stack.
861 void
862 mono_pop_lmf (MonoLMF *lmf)
864 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
868 * mono_jit_thread_attach:
870 * Called by Xamarin.Mac and other products. Attach thread to runtime if
871 * needed and switch to @domain.
873 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
875 * If the thread is newly-attached, put into GC Safe mode.
877 * @return the original domain which needs to be restored, or NULL.
879 MonoDomain*
880 mono_jit_thread_attach (MonoDomain *domain)
882 MonoDomain *orig;
883 gboolean attached;
885 if (!domain) {
886 /* Happens when called from AOTed code which is only used in the root domain. */
887 domain = mono_get_root_domain ();
890 g_assert (domain);
892 attached = mono_tls_get_jit_tls () != NULL;
894 if (!attached) {
895 mono_thread_attach (domain);
897 // #678164
898 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
900 /* mono_jit_thread_attach is external-only and not called by
901 * the runtime on any of our own threads. So if we get here,
902 * the thread is running native code - leave it in GC Safe mode
903 * and leave it to the n2m invoke wrappers or MONO_API entry
904 * points to switch to GC Unsafe.
906 MONO_STACKDATA (stackdata);
907 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
910 orig = mono_domain_get ();
911 if (orig != domain)
912 mono_domain_set (domain, TRUE);
914 return orig != domain ? orig : NULL;
918 * mono_jit_set_domain:
920 * Set domain to @domain if @domain is not null
922 void
923 mono_jit_set_domain (MonoDomain *domain)
925 g_assert (!mono_threads_is_blocking_transition_enabled ());
927 if (domain)
928 mono_domain_set (domain, TRUE);
932 * mono_thread_abort:
933 * \param obj exception object
934 * Abort the thread, print exception information and stack trace
936 static void
937 mono_thread_abort (MonoObject *obj)
939 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
941 /* handle_remove should be eventually called for this thread, too
942 g_free (jit_tls);*/
944 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
945 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
946 ((obj->vtable->klass) == mono_class_get_appdomain_unloaded_exception_class () &&
947 mono_thread_info_current ()->runtime_thread)) {
948 mono_thread_exit ();
949 } else {
950 mono_invoke_unhandled_exception_hook (obj);
954 static MonoJitTlsData*
955 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
957 MonoJitTlsData *jit_tls;
958 MonoLMF *lmf;
960 jit_tls = mono_tls_get_jit_tls ();
961 if (jit_tls)
962 return jit_tls;
964 jit_tls = g_new0 (MonoJitTlsData, 1);
966 jit_tls->abort_func = abort_func;
967 jit_tls->end_of_stack = stack_start;
969 mono_set_jit_tls (jit_tls);
971 lmf = g_new0 (MonoLMF, 1);
972 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
974 jit_tls->first_lmf = lmf;
976 mono_set_lmf_addr (&jit_tls->lmf);
978 jit_tls->lmf = lmf;
980 #ifdef MONO_ARCH_HAVE_TLS_INIT
981 mono_arch_tls_init ();
982 #endif
984 mono_setup_altstack (jit_tls);
986 return jit_tls;
989 static void
990 free_jit_tls_data (MonoJitTlsData *jit_tls)
992 //This happens during AOT cuz the thread is never attached
993 if (!jit_tls)
994 return;
995 mono_arch_free_jit_tls_data (jit_tls);
996 mono_free_altstack (jit_tls);
998 g_free (jit_tls->first_lmf);
999 g_free (jit_tls->interp_context);
1000 g_free (jit_tls);
1003 static void
1004 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
1006 MonoThreadInfo *thread;
1007 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
1008 thread = mono_thread_info_current_unchecked ();
1009 if (thread)
1010 thread->jit_data = jit_tls;
1012 mono_arch_cpu_init ();
1015 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
1017 static void
1018 mono_thread_abort_dummy (MonoObject *obj)
1020 if (mono_thread_attach_aborted_cb)
1021 mono_thread_attach_aborted_cb (obj);
1022 else
1023 mono_thread_abort (obj);
1026 static void
1027 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
1029 MonoThreadInfo *thread;
1030 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
1031 thread = mono_thread_info_current_unchecked ();
1032 if (thread)
1033 thread->jit_data = jit_tls;
1035 mono_arch_cpu_init ();
1038 static void
1039 mini_thread_cleanup (MonoNativeThreadId tid)
1041 MonoJitTlsData *jit_tls = NULL;
1042 MonoThreadInfo *info;
1044 info = mono_thread_info_current_unchecked ();
1046 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1047 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1048 * not a trivial thing.
1050 * The current offender is mono_thread_manage which cleanup threads from the outside.
1052 if (info && mono_thread_info_get_tid (info) == tid) {
1053 jit_tls = info->jit_data;
1054 info->jit_data = NULL;
1056 mono_set_jit_tls (NULL);
1058 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1059 if (mono_get_lmf ()) {
1060 mono_set_lmf (NULL);
1061 mono_set_lmf_addr (NULL);
1063 } else {
1064 info = mono_thread_info_lookup (tid);
1065 if (info) {
1066 jit_tls = info->jit_data;
1067 info->jit_data = NULL;
1069 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1072 if (jit_tls)
1073 free_jit_tls_data (jit_tls);
1076 MonoJumpInfo *
1077 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1079 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1081 ji->ip.i = ip;
1082 ji->type = type;
1083 ji->data.target = target;
1084 ji->next = list;
1086 return ji;
1089 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1091 static const char* const patch_info_str[] = {
1092 #define PATCH_INFO(a,b) "" #a,
1093 #include "patch-info.h"
1094 #undef PATCH_INFO
1097 const char*
1098 mono_ji_type_to_string (MonoJumpInfoType type)
1100 return patch_info_str [type];
1103 void
1104 mono_print_ji (const MonoJumpInfo *ji)
1106 switch (ji->type) {
1107 case MONO_PATCH_INFO_RGCTX_FETCH: {
1108 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1110 printf ("[RGCTX_FETCH ");
1111 mono_print_ji (entry->data);
1112 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1113 break;
1115 case MONO_PATCH_INFO_METHODCONST: {
1116 char *s = mono_method_full_name (ji->data.method, TRUE);
1117 printf ("[METHODCONST - %s]", s);
1118 g_free (s);
1119 break;
1121 case MONO_PATCH_INFO_JIT_ICALL: {
1122 printf ("[JIT_ICALL - %s]", ji->data.name);
1123 break;
1125 case MONO_PATCH_INFO_CLASS: {
1126 char *name = mono_class_full_name (ji->data.klass);
1127 printf ("[CLASS - %s]", name);
1128 g_free (name);
1129 break;
1131 default:
1132 printf ("[%s]", patch_info_str [ji->type]);
1133 break;
1137 #else
1139 const char*
1140 mono_ji_type_to_string (MonoJumpInfoType type)
1142 return "";
1145 void
1146 mono_print_ji (const MonoJumpInfo *ji)
1150 #endif
1153 * mono_patch_info_dup_mp:
1155 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1157 MonoJumpInfo*
1158 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1160 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1161 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1163 switch (patch_info->type) {
1164 case MONO_PATCH_INFO_RVA:
1165 case MONO_PATCH_INFO_LDSTR:
1166 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1167 case MONO_PATCH_INFO_LDTOKEN:
1168 case MONO_PATCH_INFO_DECLSEC:
1169 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1170 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1171 break;
1172 case MONO_PATCH_INFO_SWITCH:
1173 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1174 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1175 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1176 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1177 break;
1178 case MONO_PATCH_INFO_RGCTX_FETCH:
1179 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1180 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1181 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1182 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1183 break;
1184 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1185 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1186 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1187 break;
1188 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1189 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1190 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1191 break;
1192 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1193 MonoGSharedVtMethodInfo *info;
1194 MonoGSharedVtMethodInfo *oinfo;
1195 int i;
1197 oinfo = patch_info->data.gsharedvt_method;
1198 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1199 res->data.gsharedvt_method = info;
1200 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1201 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1202 for (i = 0; i < oinfo->num_entries; ++i) {
1203 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1204 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1206 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1208 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1209 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1210 break;
1212 case MONO_PATCH_INFO_VIRT_METHOD: {
1213 MonoJumpInfoVirtMethod *info;
1214 MonoJumpInfoVirtMethod *oinfo;
1216 oinfo = patch_info->data.virt_method;
1217 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1218 res->data.virt_method = info;
1219 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1220 break;
1222 default:
1223 break;
1226 return res;
1229 guint
1230 mono_patch_info_hash (gconstpointer data)
1232 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1234 switch (ji->type) {
1235 case MONO_PATCH_INFO_RVA:
1236 case MONO_PATCH_INFO_LDSTR:
1237 case MONO_PATCH_INFO_LDTOKEN:
1238 case MONO_PATCH_INFO_DECLSEC:
1239 return (ji->type << 8) | ji->data.token->token;
1240 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1241 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1242 case MONO_PATCH_INFO_JIT_ICALL:
1243 return (ji->type << 8) | g_str_hash (ji->data.name);
1244 case MONO_PATCH_INFO_VTABLE:
1245 case MONO_PATCH_INFO_CLASS:
1246 case MONO_PATCH_INFO_IID:
1247 case MONO_PATCH_INFO_ADJUSTED_IID:
1248 case MONO_PATCH_INFO_METHODCONST:
1249 case MONO_PATCH_INFO_METHOD:
1250 case MONO_PATCH_INFO_METHOD_JUMP:
1251 case MONO_PATCH_INFO_METHOD_FTNDESC:
1252 case MONO_PATCH_INFO_IMAGE:
1253 case MONO_PATCH_INFO_ICALL_ADDR:
1254 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1255 case MONO_PATCH_INFO_FIELD:
1256 case MONO_PATCH_INFO_SFLDA:
1257 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1258 case MONO_PATCH_INFO_METHOD_RGCTX:
1259 case MONO_PATCH_INFO_SIGNATURE:
1260 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1261 case MONO_PATCH_INFO_AOT_JIT_INFO:
1262 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1263 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1264 return (ji->type << 8) | (gssize)ji->data.target;
1265 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1266 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1267 case MONO_PATCH_INFO_RGCTX_FETCH:
1268 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1269 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1271 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1273 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1274 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1275 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1276 case MONO_PATCH_INFO_GC_NURSERY_START:
1277 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1278 case MONO_PATCH_INFO_GOT_OFFSET:
1279 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1280 case MONO_PATCH_INFO_AOT_MODULE:
1281 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1282 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1283 return (ji->type << 8);
1284 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1285 return (ji->type << 8) | (ji->data.index);
1286 case MONO_PATCH_INFO_SWITCH:
1287 return (ji->type << 8) | ji->data.table->table_size;
1288 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1289 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1290 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1291 /* Hash on the selector name */
1292 return g_str_hash (ji->data.target);
1293 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1294 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1295 case MONO_PATCH_INFO_LDSTR_LIT:
1296 return g_str_hash (ji->data.target);
1297 case MONO_PATCH_INFO_VIRT_METHOD: {
1298 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1300 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1302 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1303 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1304 return (ji->type << 8) | g_str_hash (ji->data.target);
1305 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1306 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1307 default:
1308 printf ("info type: %d\n", ji->type);
1309 mono_print_ji (ji); printf ("\n");
1310 g_assert_not_reached ();
1311 return 0;
1316 * mono_patch_info_equal:
1318 * This might fail to recognize equivalent patches, i.e. floats, so its only
1319 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1320 * in AOT.
1322 gint
1323 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1325 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1326 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1328 if (ji1->type != ji2->type)
1329 return 0;
1331 switch (ji1->type) {
1332 case MONO_PATCH_INFO_RVA:
1333 case MONO_PATCH_INFO_LDSTR:
1334 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1335 case MONO_PATCH_INFO_LDTOKEN:
1336 case MONO_PATCH_INFO_DECLSEC:
1337 if ((ji1->data.token->image != ji2->data.token->image) ||
1338 (ji1->data.token->token != ji2->data.token->token) ||
1339 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1340 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1341 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1342 return 0;
1343 break;
1344 case MONO_PATCH_INFO_JIT_ICALL:
1345 return g_str_equal (ji1->data.name, ji2->data.name);
1346 case MONO_PATCH_INFO_RGCTX_FETCH:
1347 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1348 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1349 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1351 return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
1353 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1354 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1355 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1357 return c1->sig == c2->sig && c1->method == c2->method;
1359 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1360 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1361 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1362 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;
1363 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1364 return ji1->data.index == ji2->data.index;
1365 case MONO_PATCH_INFO_VIRT_METHOD:
1366 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1367 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1368 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1369 if (ji1->data.target == ji2->data.target)
1370 return 1;
1371 return strcmp ((const char*)ji1->data.target, (const char*)ji2->data.target) == 0 ? 1 : 0;
1372 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1373 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1374 default:
1375 if (ji1->data.target != ji2->data.target)
1376 return 0;
1377 break;
1380 return 1;
1383 gpointer
1384 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1386 unsigned char *ip = patch_info->ip.i + code;
1387 gconstpointer target = NULL;
1389 error_init (error);
1391 switch (patch_info->type) {
1392 case MONO_PATCH_INFO_BB:
1394 * FIXME: This could be hit for methods without a prolog. Should use -1
1395 * but too much code depends on a 0 initial value.
1397 //g_assert (patch_info->data.bb->native_offset);
1398 target = patch_info->data.bb->native_offset + code;
1399 break;
1400 case MONO_PATCH_INFO_ABS:
1401 target = patch_info->data.target;
1402 break;
1403 case MONO_PATCH_INFO_LABEL:
1404 target = patch_info->data.inst->inst_c0 + code;
1405 break;
1406 case MONO_PATCH_INFO_IP:
1407 target = ip;
1408 break;
1409 case MONO_PATCH_INFO_METHOD_REL:
1410 target = code + patch_info->data.offset;
1411 break;
1412 case MONO_PATCH_INFO_JIT_ICALL: {
1413 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1414 if (!mi) {
1415 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL %s", patch_info->data.name);
1416 g_assert_not_reached ();
1418 target = mono_icall_get_wrapper (mi);
1419 break;
1421 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1422 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1423 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1424 if (!mi) {
1425 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1426 g_assert_not_reached ();
1428 target = mi->func;
1429 break;
1431 case MONO_PATCH_INFO_METHOD_JUMP:
1432 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1433 if (!mono_error_ok (error))
1434 return NULL;
1435 break;
1436 case MONO_PATCH_INFO_METHOD:
1437 if (patch_info->data.method == method) {
1438 target = code;
1439 } else {
1440 /* get the trampoline to the method from the domain */
1441 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1442 if (!mono_error_ok (error))
1443 return NULL;
1445 break;
1446 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1448 * Return an ftndesc for either AOTed code, or for an interp entry.
1450 target = mini_llvmonly_load_method_ftndesc (patch_info->data.method, FALSE, FALSE, error);
1451 return_val_if_nok (error, NULL);
1452 break;
1454 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1455 gpointer code_slot;
1457 mono_domain_lock (domain);
1458 if (!domain_jit_info (domain)->method_code_hash)
1459 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1460 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1461 if (!code_slot) {
1462 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1463 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1465 mono_domain_unlock (domain);
1466 target = code_slot;
1467 break;
1469 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1470 target = (gpointer)&mono_polling_required;
1471 break;
1472 case MONO_PATCH_INFO_SWITCH: {
1473 gpointer *jump_table;
1474 int i;
1475 if (method && method->dynamic) {
1476 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1477 } else {
1478 if (mono_aot_only) {
1479 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1480 } else {
1481 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1485 for (i = 0; i < patch_info->data.table->table_size; i++) {
1486 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1489 target = jump_table;
1490 break;
1492 case MONO_PATCH_INFO_METHODCONST:
1493 case MONO_PATCH_INFO_CLASS:
1494 case MONO_PATCH_INFO_IMAGE:
1495 case MONO_PATCH_INFO_FIELD:
1496 case MONO_PATCH_INFO_SIGNATURE:
1497 case MONO_PATCH_INFO_AOT_MODULE:
1498 target = patch_info->data.target;
1499 break;
1500 case MONO_PATCH_INFO_IID:
1501 mono_class_init_internal (patch_info->data.klass);
1502 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1503 break;
1504 case MONO_PATCH_INFO_ADJUSTED_IID:
1505 mono_class_init_internal (patch_info->data.klass);
1506 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1507 break;
1508 case MONO_PATCH_INFO_VTABLE:
1509 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1510 mono_error_assert_ok (error);
1511 break;
1512 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1513 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1515 if (del_tramp->is_virtual)
1516 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1517 else
1518 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1519 break;
1521 case MONO_PATCH_INFO_SFLDA: {
1522 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1523 mono_error_assert_ok (error);
1525 if (mono_class_field_is_special_static (patch_info->data.field)) {
1526 gpointer addr = NULL;
1528 mono_domain_lock (domain);
1529 if (domain->special_static_fields)
1530 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1531 mono_domain_unlock (domain);
1532 g_assert (addr);
1533 return addr;
1536 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1537 /* Done by the generated code */
1539 else {
1540 if (run_cctors) {
1541 if (!mono_runtime_class_init_full (vtable, error)) {
1542 return NULL;
1546 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1547 break;
1549 case MONO_PATCH_INFO_RVA: {
1550 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1551 guint32 rva;
1553 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1554 target = mono_image_rva_map (patch_info->data.token->image, rva);
1555 break;
1557 case MONO_PATCH_INFO_R4:
1558 case MONO_PATCH_INFO_R8:
1559 target = patch_info->data.target;
1560 break;
1561 case MONO_PATCH_INFO_EXC_NAME:
1562 target = patch_info->data.name;
1563 break;
1564 case MONO_PATCH_INFO_LDSTR:
1565 target =
1566 mono_ldstr_checked (domain, patch_info->data.token->image,
1567 mono_metadata_token_index (patch_info->data.token->token), error);
1568 break;
1569 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1570 gpointer handle;
1571 MonoClass *handle_class;
1573 handle = mono_ldtoken_checked (patch_info->data.token->image,
1574 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1575 if (!mono_error_ok (error))
1576 return NULL;
1577 mono_class_init_internal (handle_class);
1578 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType *)handle));
1580 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1581 if (!mono_error_ok (error))
1582 return NULL;
1583 break;
1585 case MONO_PATCH_INFO_LDTOKEN: {
1586 gpointer handle;
1587 MonoClass *handle_class;
1589 handle = mono_ldtoken_checked (patch_info->data.token->image,
1590 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1591 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1592 mono_class_init_internal (handle_class);
1594 target = handle;
1595 break;
1597 case MONO_PATCH_INFO_DECLSEC:
1598 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1599 break;
1600 case MONO_PATCH_INFO_ICALL_ADDR:
1601 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1602 /* run_cctors == 0 -> AOT */
1603 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1604 const char *exc_class;
1605 const char *exc_arg;
1607 if (run_cctors) {
1608 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1609 if (!target) {
1610 if (mono_aot_only) {
1611 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1612 return NULL;
1614 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));
1616 } else {
1617 target = NULL;
1619 } else {
1620 target = mono_lookup_internal_call (patch_info->data.method);
1622 if (!target && run_cctors)
1623 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1625 break;
1626 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1627 target = mono_thread_interruption_request_flag ();
1628 break;
1629 case MONO_PATCH_INFO_METHOD_RGCTX:
1630 target = mini_method_get_rgctx (patch_info->data.method);
1631 break;
1632 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1633 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1635 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1636 break;
1638 case MONO_PATCH_INFO_BB_OVF:
1639 case MONO_PATCH_INFO_EXC_OVF:
1640 case MONO_PATCH_INFO_GOT_OFFSET:
1641 case MONO_PATCH_INFO_NONE:
1642 break;
1643 case MONO_PATCH_INFO_RGCTX_FETCH: {
1644 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1646 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1647 break;
1649 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1650 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1651 if (!run_cctors)
1652 /* AOT, not needed */
1653 target = NULL;
1654 else
1655 target = mono_arch_get_seq_point_info (domain, code);
1656 break;
1657 #endif
1658 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1659 int card_table_shift_bits;
1660 gpointer card_table_mask;
1662 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1663 break;
1665 case MONO_PATCH_INFO_GC_NURSERY_START: {
1666 int shift_bits;
1667 size_t size;
1669 target = mono_gc_get_nursery (&shift_bits, &size);
1670 break;
1672 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1673 int shift_bits;
1674 size_t size;
1676 mono_gc_get_nursery (&shift_bits, &size);
1678 target = (gpointer)(gssize)shift_bits;
1679 break;
1681 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1682 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1683 break;
1685 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1686 target = NULL;
1687 break;
1689 case MONO_PATCH_INFO_LDSTR_LIT: {
1690 int len;
1691 char *s;
1693 len = strlen ((const char *)patch_info->data.target);
1694 s = (char *)mono_domain_alloc0 (domain, len + 1);
1695 memcpy (s, patch_info->data.target, len);
1696 target = s;
1698 break;
1700 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1701 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1702 break;
1703 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1704 target = mono_tls_get_tls_getter ((MonoTlsKey)patch_info->data.index, FALSE);
1705 break;
1706 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1707 target = mono_tls_get_tls_setter ((MonoTlsKey)patch_info->data.index, FALSE);
1708 break;
1709 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1710 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1711 break;
1713 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1714 target = (gpointer) &mono_profiler_state.exception_clause_count;
1715 break;
1717 default:
1718 g_assert_not_reached ();
1721 return (gpointer)target;
1725 * mini_register_jump_site:
1727 * Register IP as a jump/tailcall site which calls METHOD.
1728 * This is needed because common_call_trampoline () cannot patch
1729 * the call site because the caller ip is not available for jumps.
1731 void
1732 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1734 MonoJumpList *jlist;
1736 MonoMethod *shared_method = mini_method_to_shared (method);
1737 method = shared_method ? shared_method : method;
1739 mono_domain_lock (domain);
1740 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1741 if (!jlist) {
1742 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1743 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1745 jlist->list = g_slist_prepend (jlist->list, ip);
1746 mono_domain_unlock (domain);
1750 * mini_patch_jump_sites:
1752 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1754 void
1755 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1757 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1759 if (!hash)
1760 return;
1762 MonoJumpInfo patch_info;
1763 MonoJumpList *jlist;
1764 GSList *tmp;
1766 /* The caller/callee might use different instantiations */
1767 MonoMethod *shared_method = mini_method_to_shared (method);
1768 method = shared_method ? shared_method : method;
1770 mono_domain_lock (domain);
1771 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1772 if (jlist)
1773 g_hash_table_remove (hash, method);
1774 mono_domain_unlock (domain);
1775 if (jlist) {
1776 patch_info.next = NULL;
1777 patch_info.ip.i = 0;
1778 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1779 patch_info.data.method = method;
1781 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1782 for (tmp = jlist->list; tmp; tmp = tmp->next)
1783 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1784 #else
1785 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1786 // for gshared methods
1787 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1788 ERROR_DECL (error);
1789 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1790 mono_error_assert_ok (error);
1792 #endif
1796 void
1797 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1799 MonoGenericInst *inst;
1800 int i;
1802 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1804 if (context && context->class_inst) {
1805 inst = context->class_inst;
1806 for (i = 0; i < inst->type_argc; ++i) {
1807 MonoType *type = inst->type_argv [i];
1809 if (mini_is_gsharedvt_gparam (type))
1810 gsctx->is_gsharedvt = TRUE;
1813 if (context && context->method_inst) {
1814 inst = context->method_inst;
1816 for (i = 0; i < inst->type_argc; ++i) {
1817 MonoType *type = inst->type_argv [i];
1819 if (mini_is_gsharedvt_gparam (type))
1820 gsctx->is_gsharedvt = TRUE;
1826 * LOCKING: Acquires the jit code hash lock.
1828 MonoJitInfo*
1829 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1831 MonoJitInfo *ji;
1832 static gboolean inited = FALSE;
1833 static int lookups = 0;
1834 static int failed_lookups = 0;
1836 mono_domain_jit_code_hash_lock (domain);
1837 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1838 if (!ji && shared) {
1839 /* Try generic sharing */
1840 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1841 if (ji && !ji->has_generic_jit_info)
1842 ji = NULL;
1843 if (!inited) {
1844 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1845 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1846 inited = TRUE;
1849 ++lookups;
1850 if (!ji)
1851 ++failed_lookups;
1853 mono_domain_jit_code_hash_unlock (domain);
1855 return ji;
1858 static MonoJitInfo*
1859 lookup_method (MonoDomain *domain, MonoMethod *method)
1861 ERROR_DECL (error);
1862 MonoJitInfo *ji;
1863 MonoMethod *shared;
1865 ji = mini_lookup_method (domain, method, NULL);
1867 if (!ji) {
1868 if (!mono_method_is_generic_sharable (method, FALSE))
1869 return NULL;
1870 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1871 mono_error_assert_ok (error);
1872 ji = mini_lookup_method (domain, method, shared);
1875 return ji;
1878 MonoClass*
1879 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1881 ERROR_DECL (error);
1882 MonoClass *klass;
1884 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1885 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1886 if (context) {
1887 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1888 mono_error_cleanup (error); /* FIXME don't swallow the error */
1890 } else {
1891 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1892 mono_error_cleanup (error); /* FIXME don't swallow the error */
1894 if (klass)
1895 mono_class_init_internal (klass);
1896 return klass;
1899 #if ENABLE_JIT_MAP
1900 static FILE* perf_map_file;
1902 void
1903 mono_enable_jit_map (void)
1905 if (!perf_map_file) {
1906 char name [64];
1907 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1908 unlink (name);
1909 perf_map_file = fopen (name, "w");
1913 void
1914 mono_emit_jit_tramp (void *start, int size, const char *desc)
1916 if (perf_map_file)
1917 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1920 void
1921 mono_emit_jit_map (MonoJitInfo *jinfo)
1923 if (perf_map_file) {
1924 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1925 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1926 g_free (name);
1930 gboolean
1931 mono_jit_map_is_enabled (void)
1933 return perf_map_file != NULL;
1936 #endif
1938 static void
1939 no_gsharedvt_in_wrapper (void)
1941 g_assert_not_reached ();
1945 Overall algorithm:
1947 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.
1948 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1949 Dependency management in this case is too complex to justify implementing it.
1951 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1953 TODO:
1954 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1955 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1956 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1957 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1959 typedef struct {
1960 MonoMethod *method;
1961 MonoDomain *domain;
1962 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1963 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1964 int threads_waiting; /* Number of threads waiting on this job */
1965 gboolean has_cond; /* True if @cond was initialized */
1966 gboolean done; /* True if the method finished JIT'ing */
1967 MonoCoopCond cond; /* Cond sleeping threads wait one */
1968 } JitCompilationEntry;
1970 typedef struct {
1971 GPtrArray *in_flight_methods; //JitCompilationEntry*
1972 MonoCoopMutex lock;
1973 } JitCompilationData;
1976 Timeout, in millisecounds, that we wait other threads to finish JITing.
1977 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.
1979 #define MAX_JIT_TIMEOUT_MS 1000
1982 static JitCompilationData compilation_data;
1983 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
1985 static void
1986 mini_jit_init_job_control (void)
1988 mono_coop_mutex_init (&compilation_data.lock);
1989 compilation_data.in_flight_methods = g_ptr_array_new ();
1992 static void
1993 lock_compilation_data (void)
1995 mono_coop_mutex_lock (&compilation_data.lock);
1998 static void
1999 unlock_compilation_data (void)
2001 mono_coop_mutex_unlock (&compilation_data.lock);
2004 static JitCompilationEntry*
2005 find_method (MonoMethod *method, MonoDomain *domain)
2007 int i;
2008 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
2009 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
2010 if (e->method == method && e->domain == domain)
2011 return e;
2014 return NULL;
2017 static void
2018 add_current_thread (MonoJitTlsData *jit_tls)
2020 ++jit_tls->active_jit_methods;
2023 static void
2024 unref_jit_entry (JitCompilationEntry *entry)
2026 --entry->ref_count;
2027 if (entry->ref_count)
2028 return;
2029 if (entry->has_cond)
2030 mono_coop_cond_destroy (&entry->cond);
2031 g_free (entry);
2035 * Returns true if this method waited successfully for another thread to JIT it
2037 static gboolean
2038 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2040 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2041 JitCompilationEntry *entry;
2043 static gboolean inited;
2044 if (!inited) {
2045 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2046 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2047 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2048 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2049 inited = TRUE;
2052 lock_compilation_data ();
2054 if (!(entry = find_method (method, domain))) {
2055 entry = g_new0 (JitCompilationEntry, 1);
2056 entry->method = method;
2057 entry->domain = domain;
2058 entry->compilation_count = entry->ref_count = 1;
2059 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2060 g_assert (find_method (method, domain) == entry);
2061 add_current_thread (jit_tls);
2063 unlock_compilation_data ();
2064 return FALSE;
2065 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2066 //We can't suspend the current thread if it's already JITing a method.
2067 //Dependency management is too compilated and we want to get rid of this anyways.
2069 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2070 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2072 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2073 ++entry->compilation_count;
2074 ++jit_methods_multiple;
2075 ++jit_tls->active_jit_methods;
2077 unlock_compilation_data ();
2078 return FALSE;
2079 } else {
2080 ++jit_methods_waited;
2081 ++entry->ref_count;
2083 if (!entry->has_cond) {
2084 mono_coop_cond_init (&entry->cond);
2085 entry->has_cond = TRUE;
2088 while (TRUE) {
2089 ++entry->threads_waiting;
2091 g_assert (entry->has_cond);
2092 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2093 --entry->threads_waiting;
2095 if (entry->done) {
2096 unref_jit_entry (entry);
2097 unlock_compilation_data ();
2098 return TRUE;
2099 } else {
2100 //We hit the timeout or a spurious wakeup, fallback to JITing
2101 g_assert (entry->ref_count > 1);
2102 unref_jit_entry (entry);
2103 ++jit_spurious_wakeups_or_timeouts;
2105 ++entry->compilation_count;
2106 ++jit_methods_multiple;
2107 ++jit_tls->active_jit_methods;
2109 unlock_compilation_data ();
2110 return FALSE;
2116 static void
2117 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2119 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2121 lock_compilation_data ();
2123 g_assert (jit_tls->active_jit_methods > 0);
2124 --jit_tls->active_jit_methods;
2126 JitCompilationEntry *entry = find_method (method, target_domain);
2127 g_assert (entry); // It would be weird to fail
2128 entry->done = TRUE;
2130 if (entry->threads_waiting) {
2131 g_assert (entry->has_cond);
2132 mono_coop_cond_broadcast (&entry->cond);
2135 if (--entry->compilation_count == 0) {
2136 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2137 unref_jit_entry (entry);
2140 unlock_compilation_data ();
2143 static MonoJitInfo*
2144 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2146 MonoDomain *domain = mono_get_root_domain ();
2147 MonoJitInfo *jinfo;
2148 guint8 *uw_info;
2149 guint32 info_len;
2151 if (info->uw_info) {
2152 uw_info = info->uw_info;
2153 info_len = info->uw_info_len;
2154 } else {
2155 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2158 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2159 jinfo->d.method = wrapper;
2160 jinfo->code_start = info->code;
2161 jinfo->code_size = info->code_size;
2162 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2164 if (!info->uw_info)
2165 g_free (uw_info);
2167 return jinfo;
2170 static gpointer
2171 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2173 MonoJitInfo *jinfo;
2174 gpointer code;
2176 if (mono_llvm_only) {
2177 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2178 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2180 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2182 * These wrappers are only created for signatures which are in the program, but
2183 * sometimes we load methods too eagerly and have to create them even if they
2184 * will never be called.
2186 return (gpointer)no_gsharedvt_in_wrapper;
2191 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2192 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2193 MonoMethod *nm;
2194 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2196 if (!piinfo->addr) {
2197 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2198 piinfo->addr = mono_lookup_internal_call (method);
2199 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2200 #ifdef HOST_WIN32
2201 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);
2202 #else
2203 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);
2204 #endif
2205 else
2206 mono_lookup_pinvoke_call (method, NULL, NULL);
2208 nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2209 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2210 return_val_if_nok (error, NULL);
2211 code = mono_get_addr_from_ftnptr (compiled_method);
2212 jinfo = mono_jit_info_table_find (target_domain, code);
2213 if (!jinfo)
2214 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2215 if (jinfo)
2216 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2217 return code;
2218 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2219 const char *name = method->name;
2220 char *full_name;
2221 MonoMethod *nm;
2223 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2224 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2225 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2226 g_assert (mi);
2228 * We need to make sure this wrapper
2229 * is compiled because it might end up
2230 * in an (M)RGCTX if generic sharing
2231 * is enabled, and would be called
2232 * indirectly. If it were a
2233 * trampoline we'd try to patch that
2234 * indirect call, which is not
2235 * possible.
2237 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2238 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2239 if (mono_llvm_only) {
2240 nm = mono_marshal_get_delegate_invoke (method, NULL);
2241 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2242 return_val_if_nok (error, NULL);
2243 return mono_get_addr_from_ftnptr (compiled_ptr);
2246 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2247 if (mono_use_interpreter)
2248 return NULL;
2250 return mono_create_delegate_trampoline (target_domain, method->klass);
2251 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2252 nm = mono_marshal_get_delegate_begin_invoke (method);
2253 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2254 return_val_if_nok (error, NULL);
2255 return mono_get_addr_from_ftnptr (compiled_ptr);
2256 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2257 nm = mono_marshal_get_delegate_end_invoke (method);
2258 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2259 return_val_if_nok (error, NULL);
2260 return mono_get_addr_from_ftnptr (compiled_ptr);
2264 full_name = mono_method_full_name (method, TRUE);
2265 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2266 g_free (full_name);
2267 return NULL;
2270 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2271 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2273 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2274 static MonoTrampInfo *in_tinfo, *out_tinfo;
2275 MonoTrampInfo *tinfo;
2276 MonoJitInfo *jinfo;
2277 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2279 if (is_in && in_tinfo)
2280 return in_tinfo->code;
2281 else if (!is_in && out_tinfo)
2282 return out_tinfo->code;
2285 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2286 * works.
2287 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2289 if (mono_ee_features.use_aot_trampolines)
2290 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2291 else
2292 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2293 jinfo = create_jit_info_for_trampoline (method, tinfo);
2294 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2295 if (is_in)
2296 in_tinfo = tinfo;
2297 else
2298 out_tinfo = tinfo;
2299 return tinfo->code;
2303 return NULL;
2306 static gpointer
2307 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2309 MonoDomain *target_domain, *domain = mono_domain_get ();
2310 MonoJitInfo *info;
2311 gpointer code = NULL, p;
2312 MonoJitInfo *ji;
2313 MonoJitICallInfo *callinfo = NULL;
2314 WrapperInfo *winfo = NULL;
2315 gboolean use_interp = FALSE;
2317 error_init (error);
2319 if (mono_ee_features.force_use_interpreter && !jit_only)
2320 use_interp = TRUE;
2321 if (!use_interp && mono_interp_only_classes) {
2322 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2323 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2324 use_interp = TRUE;
2327 if (use_interp) {
2328 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2329 if (code)
2330 return code;
2333 if (mono_llvm_only)
2334 /* Should be handled by the caller */
2335 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2338 * ICALL wrappers are handled specially, since there is only one copy of them
2339 * shared by all appdomains.
2341 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2342 winfo = mono_marshal_get_wrapper_info (method);
2343 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2344 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2345 g_assert (callinfo);
2347 /* Must be domain neutral since there is only one copy */
2348 opt |= MONO_OPT_SHARED;
2349 } else {
2350 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2351 opt &= ~MONO_OPT_SHARED;
2354 if (opt & MONO_OPT_SHARED)
2355 target_domain = mono_get_root_domain ();
2356 else
2357 target_domain = domain;
2359 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2360 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2362 g_assert (info);
2363 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2364 MonoGenericContext *ctx = NULL;
2365 if (method->is_inflated)
2366 ctx = mono_method_get_context (method);
2367 method = info->d.synchronized_inner.method;
2368 if (ctx) {
2369 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2370 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2375 lookup_start:
2376 info = lookup_method (target_domain, method);
2377 if (info) {
2378 /* We can't use a domain specific method in another domain */
2379 if (! ((domain != target_domain) && !info->domain_neutral)) {
2380 MonoVTable *vtable;
2382 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2383 vtable = mono_class_vtable_checked (domain, method->klass, error);
2384 if (!is_ok (error))
2385 return NULL;
2386 g_assert (vtable);
2387 if (!mono_runtime_class_init_full (vtable, error))
2388 return NULL;
2389 return mono_create_ftnptr (target_domain, info->code_start);
2393 #ifdef MONO_USE_AOT_COMPILER
2394 if (opt & MONO_OPT_AOT) {
2395 MonoDomain *domain = NULL;
2397 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2398 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2399 g_assert (info);
2400 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2401 /* AOT'd wrappers for interp must be owned by root domain */
2402 domain = mono_get_root_domain ();
2405 if (!domain)
2406 domain = mono_domain_get ();
2408 mono_class_init_internal (method->klass);
2410 code = mono_aot_get_method (domain, method, error);
2411 if (code) {
2412 MonoVTable *vtable;
2414 if (mono_gc_is_critical_method (method)) {
2416 * The suspend code needs to be able to lookup these methods by ip in async context,
2417 * so preload their jit info.
2419 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2420 g_assert (ji);
2424 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2425 * This is not a problem, since it will be initialized when the method is first
2426 * called by init_method ().
2428 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2429 vtable = mono_class_vtable_checked (domain, method->klass, error);
2430 mono_error_assert_ok (error);
2431 if (!mono_runtime_class_init_full (vtable, error))
2432 return NULL;
2435 if (!is_ok (error))
2436 return NULL;
2438 #endif
2440 if (!code) {
2441 code = compile_special (method, target_domain, error);
2443 if (!mono_error_ok (error))
2444 return NULL;
2447 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER) {
2448 if (mono_llvm_only) {
2449 /* Signal to the caller that AOTed code is not found */
2450 return NULL;
2452 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2454 if (!mono_error_ok (error))
2455 return NULL;
2458 if (!code) {
2459 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2460 char *full_name = mono_type_get_full_name (method->klass);
2461 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2462 g_free (full_name);
2463 return NULL;
2466 if (mono_aot_only) {
2467 char *fullname = mono_method_get_full_name (method);
2468 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);
2469 g_free (fullname);
2471 return NULL;
2474 if (wait_or_register_method_to_compile (method, target_domain))
2475 goto lookup_start;
2476 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2477 unregister_method_for_compile (method, target_domain);
2479 if (!mono_error_ok (error))
2480 return NULL;
2482 if (!code && mono_llvm_only) {
2483 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2484 g_assert_not_reached ();
2487 if (!code)
2488 return NULL;
2490 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2491 #ifndef HOST_WASM
2492 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2493 MonoDomain *d;
2496 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2498 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2499 g_assert (ji);
2501 #endif
2503 p = mono_create_ftnptr (target_domain, code);
2505 if (callinfo) {
2506 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2507 mono_loader_lock ();
2508 mono_jit_lock ();
2509 if (!callinfo->wrapper) {
2510 callinfo->wrapper = p;
2511 mono_register_jit_icall_wrapper (callinfo, p);
2513 mono_jit_unlock ();
2514 mono_loader_unlock ();
2517 return p;
2520 gpointer
2521 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2523 gpointer code;
2525 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2526 return code;
2530 * mono_jit_compile_method_jit_only:
2532 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2534 gpointer
2535 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2537 gpointer code;
2539 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2540 return code;
2543 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2544 static void
2545 invalidated_delegate_trampoline (char *desc)
2547 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2548 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2549 desc);
2551 #endif
2554 * mono_jit_free_method:
2556 * Free all memory allocated by the JIT for METHOD.
2558 static void
2559 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2561 MonoJitDynamicMethodInfo *ji;
2562 gboolean destroy = TRUE, removed;
2563 GHashTableIter iter;
2564 MonoJumpList *jlist;
2565 MonoJitDomainInfo *info = domain_jit_info (domain);
2567 g_assert (method->dynamic);
2569 if (mono_use_interpreter) {
2570 mono_domain_jit_code_hash_lock (domain);
2571 /* InterpMethod is allocated in the domain mempool. We might haven't
2572 * allocated an InterpMethod for this instance yet */
2573 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2574 mono_domain_jit_code_hash_unlock (domain);
2577 mono_domain_lock (domain);
2578 ji = mono_dynamic_code_hash_lookup (domain, method);
2579 mono_domain_unlock (domain);
2581 if (!ji)
2582 return;
2584 mono_debug_remove_method (method, domain);
2585 mono_lldb_remove_method (domain, method, ji);
2587 mono_domain_lock (domain);
2588 g_hash_table_remove (info->dynamic_code_hash, method);
2589 mono_domain_jit_code_hash_lock (domain);
2590 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2591 g_assert (removed);
2592 mono_domain_jit_code_hash_unlock (domain);
2593 g_hash_table_remove (info->jump_trampoline_hash, method);
2594 g_hash_table_remove (info->seq_points, method);
2596 ji->ji->seq_points = NULL;
2598 /* requires the domain lock - took above */
2599 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2601 /* Remove jump targets in this method */
2602 g_hash_table_iter_init (&iter, info->jump_target_hash);
2603 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2604 GSList *tmp, *remove;
2606 remove = NULL;
2607 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2608 guint8 *ip = (guint8 *)tmp->data;
2610 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2611 remove = g_slist_prepend (remove, tmp);
2613 for (tmp = remove; tmp; tmp = tmp->next) {
2614 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2616 g_slist_free (remove);
2618 mono_domain_unlock (domain);
2620 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2621 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2623 * Instead of freeing the code, change it to call an error routine
2624 * so people can fix their code.
2626 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2627 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2629 g_free (type);
2630 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2631 destroy = FALSE;
2633 #endif
2636 * This needs to be done before freeing code_mp, since the code address is the
2637 * key in the table, so if we free the code_mp first, another thread can grab the
2638 * same code address and replace our entry in the table.
2640 mono_jit_info_table_remove (domain, ji->ji);
2642 if (destroy)
2643 mono_code_manager_destroy (ji->code_mp);
2644 g_free (ji);
2647 gpointer
2648 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2650 gpointer code;
2651 MonoJitInfo *ji;
2653 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2654 if (!code) {
2655 ERROR_DECL (oerror);
2657 /* Might be AOTed code */
2658 mono_class_init_internal (method->klass);
2659 code = mono_aot_get_method (domain, method, oerror);
2660 if (code) {
2661 mono_error_assert_ok (oerror);
2662 ji = mono_jit_info_table_find (domain, code);
2663 } else {
2664 if (!is_ok (oerror))
2665 mono_error_cleanup (oerror);
2667 /* Might be interpreted */
2668 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2672 *out_ji = ji;
2674 return code;
2677 gpointer
2678 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2680 MonoDomain *target_domain;
2681 MonoJitInfo *info;
2683 if (default_opt & MONO_OPT_SHARED)
2684 target_domain = mono_get_root_domain ();
2685 else
2686 target_domain = domain;
2688 info = lookup_method (target_domain, method);
2689 if (info) {
2690 /* We can't use a domain specific method in another domain */
2691 if (! ((domain != target_domain) && !info->domain_neutral)) {
2692 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2693 if (ji)
2694 *ji = info;
2695 return info->code_start;
2699 if (ji)
2700 *ji = NULL;
2701 return NULL;
2704 static guint32 bisect_opt = 0;
2705 static GHashTable *bisect_methods_hash = NULL;
2707 void
2708 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2710 FILE *file;
2711 char method_name [2048];
2713 bisect_opt = opt;
2714 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2715 g_assert (bisect_methods_hash);
2717 file = fopen (method_list_filename, "r");
2718 g_assert (file);
2720 while (fgets (method_name, sizeof (method_name), file)) {
2721 size_t len = strlen (method_name);
2722 g_assert (len > 0);
2723 g_assert (method_name [len - 1] == '\n');
2724 method_name [len - 1] = 0;
2725 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2727 g_assert (feof (file));
2730 gboolean mono_do_single_method_regression = FALSE;
2731 guint32 mono_single_method_regression_opt = 0;
2732 MonoMethod *mono_current_single_method;
2733 GSList *mono_single_method_list;
2734 GHashTable *mono_single_method_hash;
2736 guint32
2737 mono_get_optimizations_for_method (MonoMethod *method, guint32 opt)
2739 g_assert (method);
2741 if (bisect_methods_hash) {
2742 char *name = mono_method_full_name (method, TRUE);
2743 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2744 g_free (name);
2745 if (res)
2746 return opt | bisect_opt;
2748 if (!mono_do_single_method_regression)
2749 return opt;
2750 if (!mono_current_single_method) {
2751 if (!mono_single_method_hash)
2752 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2753 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2754 g_hash_table_insert (mono_single_method_hash, method, method);
2755 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2757 return opt;
2759 if (method == mono_current_single_method)
2760 return mono_single_method_regression_opt;
2761 return opt;
2764 gpointer
2765 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2767 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2770 typedef struct {
2771 MonoMethod *method;
2772 gpointer compiled_method;
2773 gpointer runtime_invoke;
2774 MonoVTable *vtable;
2775 MonoDynCallInfo *dyn_call_info;
2776 MonoClass *ret_box_class;
2777 MonoMethodSignature *sig;
2778 gboolean gsharedvt_invoke;
2779 gboolean use_interp;
2780 gpointer *wrapper_arg;
2781 } RuntimeInvokeInfo;
2783 static RuntimeInvokeInfo*
2784 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2786 MonoMethod *invoke;
2787 RuntimeInvokeInfo *info;
2789 info = g_new0 (RuntimeInvokeInfo, 1);
2790 info->compiled_method = compiled_method;
2791 info->use_interp = use_interp;
2792 if (mono_llvm_only && method->string_ctor)
2793 info->sig = mono_marshal_get_string_ctor_signature (method);
2794 else
2795 info->sig = mono_method_signature_internal (method);
2797 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2798 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2799 if (!mono_error_ok (error))
2800 return NULL;
2801 g_assert (info->vtable);
2803 MonoMethodSignature *sig = info->sig;
2804 MonoType *ret_type;
2807 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2808 * in full-aot mode, so we use a slower, but more generic wrapper if
2809 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2811 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2812 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2813 gboolean supported = TRUE;
2814 int i;
2816 if (method->string_ctor)
2817 sig = mono_marshal_get_string_ctor_signature (method);
2819 for (i = 0; i < sig->param_count; ++i) {
2820 MonoType *t = sig->params [i];
2822 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
2823 supported = FALSE;
2826 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2827 supported = FALSE;
2829 if (supported) {
2830 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2831 if (mini_debug_options.dyn_runtime_invoke)
2832 g_assert (info->dyn_call_info);
2835 #endif
2837 ret_type = sig->ret;
2838 switch (ret_type->type) {
2839 case MONO_TYPE_VOID:
2840 break;
2841 case MONO_TYPE_I1:
2842 case MONO_TYPE_U1:
2843 case MONO_TYPE_I2:
2844 case MONO_TYPE_U2:
2845 case MONO_TYPE_I4:
2846 case MONO_TYPE_U4:
2847 case MONO_TYPE_I:
2848 case MONO_TYPE_U:
2849 case MONO_TYPE_I8:
2850 case MONO_TYPE_U8:
2851 case MONO_TYPE_BOOLEAN:
2852 case MONO_TYPE_CHAR:
2853 case MONO_TYPE_R4:
2854 case MONO_TYPE_R8:
2855 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2856 break;
2857 case MONO_TYPE_PTR:
2858 info->ret_box_class = mono_defaults.int_class;
2859 break;
2860 case MONO_TYPE_STRING:
2861 case MONO_TYPE_CLASS:
2862 case MONO_TYPE_ARRAY:
2863 case MONO_TYPE_SZARRAY:
2864 case MONO_TYPE_OBJECT:
2865 break;
2866 case MONO_TYPE_GENERICINST:
2867 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2868 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2869 break;
2870 case MONO_TYPE_VALUETYPE:
2871 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2872 break;
2873 default:
2874 g_assert_not_reached ();
2875 break;
2878 if (info->use_interp)
2879 return info;
2881 if (!info->dyn_call_info) {
2882 if (mono_llvm_only) {
2883 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2884 g_assert_not_reached ();
2885 #endif
2886 info->gsharedvt_invoke = TRUE;
2887 if (!callee_gsharedvt) {
2888 /* Invoke a gsharedvt out wrapper instead */
2889 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2890 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2892 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2893 info->wrapper_arg [0] = mini_llvmonly_add_method_wrappers (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2895 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2896 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2897 g_free (wrapper_sig);
2899 info->compiled_method = mono_jit_compile_method (wrapper, error);
2900 if (!mono_error_ok (error)) {
2901 g_free (info);
2902 return NULL;
2904 } else {
2905 /* Gsharedvt methods can be invoked the same way */
2906 /* The out wrapper has the same signature as the compiled gsharedvt method */
2907 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2909 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
2911 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2912 g_free (wrapper_sig);
2915 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2916 if (!mono_error_ok (error)) {
2917 g_free (info);
2918 return NULL;
2922 return info;
2925 static MonoObject*
2926 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2928 MonoMethodSignature *sig = info->sig;
2929 MonoDomain *domain = mono_domain_get ();
2930 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2931 gpointer *args;
2932 gpointer retval_ptr;
2933 guint8 retval [256];
2934 gpointer *param_refs;
2935 int i, pindex;
2937 error_init (error);
2939 g_assert (info->gsharedvt_invoke);
2942 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2943 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2944 * signatures, so we only have to generate runtime invoke wrappers for these
2945 * signatures.
2946 * This code also handles invocation of gsharedvt methods directly, no
2947 * out wrappers are used in that case.
2949 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2950 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2951 pindex = 0;
2953 * The runtime invoke wrappers expects pointers to primitive types, so have to
2954 * use indirections.
2956 if (sig->hasthis)
2957 args [pindex ++] = &obj;
2958 if (sig->ret->type != MONO_TYPE_VOID) {
2959 retval_ptr = (gpointer)&retval;
2960 args [pindex ++] = &retval_ptr;
2962 for (i = 0; i < sig->param_count; ++i) {
2963 MonoType *t = sig->params [i];
2965 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
2966 MonoClass *klass = mono_class_from_mono_type_internal (t);
2967 guint8 *nullable_buf;
2968 int size;
2970 size = mono_class_value_size (klass, NULL);
2971 nullable_buf = g_alloca (size);
2972 g_assert (nullable_buf);
2974 /* The argument pointed to by params [i] is either a boxed vtype or null */
2975 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2976 params [i] = nullable_buf;
2979 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2980 param_refs [i] = params [i];
2981 params [i] = &(param_refs [i]);
2983 args [pindex ++] = &params [i];
2985 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2986 args [pindex ++] = &info->wrapper_arg;
2988 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2990 runtime_invoke (NULL, args, exc, info->compiled_method);
2991 if (exc && *exc)
2992 return NULL;
2994 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2995 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2996 else
2997 return *(MonoObject**)retval;
3001 * mono_jit_runtime_invoke:
3002 * \param method: the method to invoke
3003 * \param obj: this pointer
3004 * \param params: array of parameter values.
3005 * \param exc: Set to the exception raised in the managed method.
3006 * \param error: error or caught exception object
3007 * If \p exc is NULL, \p error is thrown instead.
3008 * If coop is enabled, \p exc argument is ignored -
3009 * all exceptions are caught and propagated through \p error
3011 static MonoObject*
3012 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
3014 MonoMethod *invoke, *callee;
3015 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
3016 MonoDomain *domain = mono_domain_get ();
3017 MonoJitDomainInfo *domain_info;
3018 RuntimeInvokeInfo *info, *info2;
3019 MonoJitInfo *ji = NULL;
3020 gboolean callee_gsharedvt = FALSE;
3022 if (mono_ee_features.force_use_interpreter)
3023 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3025 error_init (error);
3026 if (exc)
3027 *exc = NULL;
3029 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
3030 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3031 return NULL;
3034 domain_info = domain_jit_info (domain);
3036 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3038 if (!info) {
3039 if (mono_security_core_clr_enabled ()) {
3041 * This might be redundant since mono_class_vtable () already does this,
3042 * but keep it just in case for moonlight.
3044 mono_class_setup_vtable (method->klass);
3045 if (mono_class_has_failure (method->klass)) {
3046 mono_error_set_for_class_failure (error, method->klass);
3047 if (exc)
3048 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3049 return NULL;
3053 gpointer compiled_method;
3055 callee = method;
3056 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3057 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3059 * Array Get/Set/Address methods. The JIT implements them using inline code
3060 * inside the runtime invoke wrappers, so no need to compile them.
3062 if (mono_aot_only) {
3064 * Call a wrapper, since the runtime invoke wrapper was not generated.
3066 MonoMethod *wrapper;
3068 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3069 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3070 callee = wrapper;
3071 } else {
3072 callee = NULL;
3076 gboolean use_interp = FALSE;
3078 if (callee) {
3079 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3080 if (!compiled_method) {
3081 g_assert (!mono_error_ok (error));
3083 if (mono_use_interpreter)
3084 use_interp = TRUE;
3085 else
3086 return NULL;
3087 } else {
3088 if (mono_llvm_only) {
3089 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3090 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3091 if (callee_gsharedvt)
3092 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3095 if (!callee_gsharedvt)
3096 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3098 } else {
3099 compiled_method = NULL;
3102 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3103 if (!mono_error_ok (error))
3104 return NULL;
3106 mono_domain_lock (domain);
3107 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3108 mono_domain_unlock (domain);
3109 if (info2) {
3110 g_free (info);
3111 info = info2;
3116 * We need this here because mono_marshal_get_runtime_invoke can place
3117 * the helper method in System.Object and not the target class.
3119 if (!mono_runtime_class_init_full (info->vtable, error)) {
3120 if (exc)
3121 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3122 return NULL;
3125 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3126 we always catch the exception and propagate it through the MonoError */
3127 gboolean catchExcInMonoError =
3128 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3129 MonoObject *invoke_exc = NULL;
3130 if (catchExcInMonoError)
3131 exc = &invoke_exc;
3133 /* The wrappers expect this to be initialized to NULL */
3134 if (exc)
3135 *exc = NULL;
3137 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3138 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3139 if (info->dyn_call_info) {
3140 if (!dyn_runtime_invoke) {
3141 mono_domain_lock (domain);
3143 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3144 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3145 if (!dyn_runtime_invoke && mono_use_interpreter) {
3146 info->use_interp = TRUE;
3147 info->dyn_call_info = NULL;
3148 } else if (!mono_error_ok (error)) {
3149 mono_domain_unlock (domain);
3150 return NULL;
3152 mono_domain_unlock (domain);
3155 if (info->dyn_call_info) {
3156 MonoMethodSignature *sig = mono_method_signature_internal (method);
3157 gpointer *args;
3158 int i, pindex, buf_size;
3159 guint8 *buf;
3160 guint8 retval [256];
3162 /* Convert the arguments to the format expected by start_dyn_call () */
3163 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3164 pindex = 0;
3165 if (sig->hasthis)
3166 args [pindex ++] = &obj;
3167 for (i = 0; i < sig->param_count; ++i) {
3168 MonoType *t = sig->params [i];
3170 if (t->byref) {
3171 args [pindex ++] = &params [i];
3172 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3173 args [pindex ++] = &params [i];
3174 } else {
3175 args [pindex ++] = params [i];
3179 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3181 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3182 buf = g_alloca (buf_size);
3183 memset (buf, 0, buf_size);
3184 g_assert (buf);
3186 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3188 dyn_runtime_invoke (buf, exc, info->compiled_method);
3189 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3191 if (catchExcInMonoError && *exc != NULL) {
3192 mono_error_set_exception_instance (error, (MonoException*) *exc);
3193 return NULL;
3196 if (info->ret_box_class)
3197 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3198 else
3199 return *(MonoObject**)retval;
3201 #endif
3203 MonoObject *result;
3205 if (info->use_interp) {
3206 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3207 return_val_if_nok (error, NULL);
3208 } else if (mono_llvm_only) {
3209 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3210 if (!is_ok (error))
3211 return NULL;
3212 } else {
3213 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3215 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3217 if (catchExcInMonoError && *exc != NULL) {
3218 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3219 mono_error_set_exception_instance (error, (MonoException*) *exc);
3221 return result;
3224 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3226 MonoException *exc = NULL;
3227 MonoJitInfo *ji;
3228 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3229 MONO_SIG_HANDLER_GET_CONTEXT;
3231 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3233 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3235 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3236 if (mono_arch_is_int_overflow (ctx, info))
3238 * The spec says this throws ArithmeticException, but MS throws the derived
3239 * OverflowException.
3241 exc = mono_get_exception_overflow ();
3242 else
3243 exc = mono_get_exception_divide_by_zero ();
3244 #else
3245 exc = mono_get_exception_divide_by_zero ();
3246 #endif
3248 if (!ji) {
3249 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3250 goto exit;
3252 mono_handle_native_crash ("SIGFPE", ctx, info);
3253 if (mono_do_crash_chaining) {
3254 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3255 goto exit;
3259 mono_arch_handle_exception (ctx, exc);
3261 exit:
3262 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3265 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3267 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3268 MONO_SIG_HANDLER_GET_CONTEXT;
3270 if (mono_runtime_get_no_exec ())
3271 exit (1);
3274 mono_handle_native_crash ("SIGILL", ctx, info);
3275 if (mono_do_crash_chaining) {
3276 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3277 return;
3280 g_assert_not_reached ();
3283 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3285 #define HAVE_SIG_INFO
3286 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3288 #ifdef MONO_SIG_HANDLER_DEBUG
3289 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3290 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3291 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3292 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3293 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3294 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3295 #endif
3297 #endif
3299 static gboolean
3300 is_addr_implicit_null_check (void *addr)
3302 /* implicit null checks are only expected to work on the first page. larger
3303 * offsets are expected to have an explicit null check */
3304 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3307 // This function is separate from mono_sigsegv_signal_handler
3308 // so debug_fault_addr can be seen in debugger stacks.
3309 #ifdef MONO_SIG_HANDLER_DEBUG
3310 MONO_NEVER_INLINE
3311 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3312 #else
3313 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3314 #endif
3316 MonoJitInfo *ji;
3317 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3318 gpointer fault_addr = NULL;
3319 #ifdef HAVE_SIG_INFO
3320 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3321 #else
3322 void *info = NULL;
3323 #endif
3324 MONO_SIG_HANDLER_GET_CONTEXT;
3326 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3327 if (mono_arch_is_single_step_event (info, ctx)) {
3328 mini_get_dbg_callbacks ()->single_step_event (ctx);
3329 return;
3330 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3331 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3332 return;
3334 #endif
3336 #if defined(HAVE_SIG_INFO)
3337 #if !defined(HOST_WIN32)
3338 fault_addr = info->si_addr;
3339 if (mono_aot_is_pagefault (info->si_addr)) {
3340 mono_aot_handle_pagefault (info->si_addr);
3341 return;
3343 #endif
3345 /* The thread might no be registered with the runtime */
3346 if (!mono_domain_get () || !jit_tls) {
3347 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3348 return;
3349 mono_handle_native_crash ("SIGSEGV", ctx, info);
3350 if (mono_do_crash_chaining) {
3351 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3352 return;
3355 #endif
3357 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3359 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3360 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3361 return;
3363 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3364 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3365 fault_addr = info->si_addr;
3366 if (fault_addr == NULL) {
3367 MonoContext mctx;
3369 mono_sigctx_to_monoctx (ctx, &mctx);
3371 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3373 #endif
3375 if (jit_tls->stack_size &&
3376 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3378 * The hard-guard page has been hit: there is not much we can do anymore
3379 * Print a hopefully clear message and abort.
3381 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3382 g_assert_not_reached ();
3383 } else {
3384 /* The original handler might not like that it is executed on an altstack... */
3385 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3386 return;
3388 if (is_addr_implicit_null_check (info->si_addr)) {
3389 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3390 } else {
3391 mono_handle_native_crash ("SIGSEGV", ctx, info);
3394 #else
3396 if (!ji) {
3397 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3398 return;
3400 mono_handle_native_crash ("SIGSEGV", ctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3402 if (mono_do_crash_chaining) {
3403 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3404 return;
3408 if (is_addr_implicit_null_check (fault_addr)) {
3409 mono_arch_handle_exception (ctx, NULL);
3410 } else {
3411 mono_handle_native_crash ("SIGSEGV", ctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3413 #endif
3416 #ifdef MONO_SIG_HANDLER_DEBUG
3418 // This function is separate from mono_sigsegv_signal_handler_debug
3419 // so debug_fault_addr can be seen in debugger stacks.
3420 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3422 #ifdef HOST_WIN32
3423 gpointer const debug_fault_addr = (gpointer)MONO_SIG_HANDLER_GET_INFO () ->ep->ExceptionRecord->ExceptionInformation [1];
3424 #elif defined (HAVE_SIG_INFO)
3425 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3426 #else
3427 #error No extra parameter is passed, not even 0, to avoid any confusion.
3428 #endif
3429 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3432 #endif // MONO_SIG_HANDLER_DEBUG
3434 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3436 MonoException *exc;
3437 MONO_SIG_HANDLER_GET_CONTEXT;
3439 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3441 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3443 mono_arch_handle_exception (ctx, exc);
3445 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3448 #ifndef DISABLE_REMOTING
3449 /* mono_jit_create_remoting_trampoline:
3450 * @method: pointer to the method info
3452 * Creates a trampoline which calls the remoting functions. This
3453 * is used in the vtable of transparent proxies.
3455 * Returns: a pointer to the newly created code
3457 static gpointer
3458 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3460 MonoMethod *nm;
3461 guint8 *addr = NULL;
3463 error_init (error);
3465 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3466 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3467 domain, NULL);
3470 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3471 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3472 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3473 else
3474 nm = method;
3475 return_val_if_nok (error, NULL);
3476 addr = (guint8 *)mono_compile_method_checked (nm, error);
3477 return_val_if_nok (error, NULL);
3478 return mono_get_addr_from_ftnptr (addr);
3480 #endif
3482 static G_GNUC_UNUSED void
3483 no_imt_trampoline (void)
3485 g_assert_not_reached ();
3488 static G_GNUC_UNUSED void
3489 no_vcall_trampoline (void)
3491 g_assert_not_reached ();
3494 static gpointer *vtable_trampolines;
3495 static int vtable_trampolines_size;
3497 gpointer
3498 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3500 int index = slot_index + MONO_IMT_SIZE;
3502 if (mono_llvm_only)
3503 return mini_llvmonly_get_vtable_trampoline (vt, slot_index, index);
3505 g_assert (slot_index >= - MONO_IMT_SIZE);
3506 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3507 mono_jit_lock ();
3508 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3509 int new_size;
3510 gpointer new_table;
3512 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3513 while (new_size <= index)
3514 new_size *= 2;
3515 new_table = g_new0 (gpointer, new_size);
3517 if (vtable_trampolines)
3518 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3519 g_free (vtable_trampolines);
3520 mono_memory_barrier ();
3521 vtable_trampolines = (void **)new_table;
3522 vtable_trampolines_size = new_size;
3524 mono_jit_unlock ();
3527 if (!vtable_trampolines [index])
3528 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3529 return vtable_trampolines [index];
3532 static gpointer
3533 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3535 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3538 static gboolean
3539 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3541 if (mono_llvm_only)
3542 return FALSE;
3544 gpointer *imt = (gpointer*)vt;
3545 imt -= MONO_IMT_SIZE;
3547 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3550 static gpointer
3551 create_delegate_method_ptr (MonoMethod *method, MonoError *error)
3553 gpointer func;
3555 if (method_is_dynamic (method)) {
3556 /* Creating a trampoline would leak memory */
3557 func = mono_compile_method_checked (method, error);
3558 return_val_if_nok (error, NULL);
3559 } else {
3560 gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
3561 return_val_if_nok (error, NULL);
3562 func = mono_create_ftnptr (mono_domain_get (), trampoline);
3564 return func;
3567 static void
3568 mini_init_delegate (MonoDelegateHandle delegate, MonoError *error)
3570 MonoDelegate *del = MONO_HANDLE_RAW (delegate);
3572 if (!del->method_ptr) {
3573 g_assert (del->method);
3574 del->method_ptr = create_delegate_method_ptr (del->method, error);
3575 return_if_nok (error);
3578 if (mono_use_interpreter)
3579 mini_get_interp_callbacks ()->init_delegate (del);
3580 if (mono_llvm_only)
3581 del->extra_arg = mini_llvmonly_get_delegate_arg (del->method, del->method_ptr);
3584 char*
3585 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3587 int abs_offset;
3589 abs_offset = offset;
3590 if (abs_offset < 0)
3591 abs_offset = - abs_offset;
3592 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3595 gpointer
3596 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3598 gboolean is_virtual_generic, is_interface, load_imt_reg;
3599 int offset, idx;
3601 static guint8 **cache = NULL;
3602 static int cache_size = 0;
3604 if (!method)
3605 return NULL;
3607 if (MONO_TYPE_ISSTRUCT (sig->ret))
3608 return NULL;
3610 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3611 is_interface = mono_class_is_interface (method->klass);
3612 load_imt_reg = is_virtual_generic || is_interface;
3614 if (is_interface)
3615 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3616 else
3617 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3619 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3620 g_assert (idx >= 0);
3622 /* Resize the cache to idx + 1 */
3623 if (cache_size < idx + 1) {
3624 mono_jit_lock ();
3625 if (cache_size < idx + 1) {
3626 guint8 **new_cache;
3627 int new_cache_size = idx + 1;
3629 new_cache = g_new0 (guint8*, new_cache_size);
3630 if (cache)
3631 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3632 g_free (cache);
3634 mono_memory_barrier ();
3635 cache = new_cache;
3636 cache_size = new_cache_size;
3638 mono_jit_unlock ();
3641 if (cache [idx])
3642 return cache [idx];
3644 /* FIXME Support more cases */
3645 if (mono_ee_features.use_aot_trampolines) {
3646 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3647 g_assert (cache [idx]);
3648 } else {
3649 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3651 return cache [idx];
3655 * mini_parse_debug_option:
3656 * @option: The option to parse.
3658 * Parses debug options for the mono runtime. The options are the same as for
3659 * the MONO_DEBUG environment variable.
3662 gboolean
3663 mini_parse_debug_option (const char *option)
3665 // Empty string is ok as consequence of appending ",foo"
3666 // without first checking for empty.
3667 if (*option == 0)
3668 return TRUE;
3670 if (!strcmp (option, "handle-sigint"))
3671 mini_debug_options.handle_sigint = TRUE;
3672 else if (!strcmp (option, "keep-delegates"))
3673 mini_debug_options.keep_delegates = TRUE;
3674 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3675 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3676 else if (!strcmp (option, "collect-pagefault-stats"))
3677 mini_debug_options.collect_pagefault_stats = TRUE;
3678 else if (!strcmp (option, "break-on-unverified"))
3679 mini_debug_options.break_on_unverified = TRUE;
3680 else if (!strcmp (option, "no-gdb-backtrace"))
3681 mini_debug_options.no_gdb_backtrace = TRUE;
3682 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3683 mini_debug_options.suspend_on_native_crash = TRUE;
3684 else if (!strcmp (option, "suspend-on-exception"))
3685 mini_debug_options.suspend_on_exception = TRUE;
3686 else if (!strcmp (option, "suspend-on-unhandled"))
3687 mini_debug_options.suspend_on_unhandled = TRUE;
3688 else if (!strcmp (option, "dont-free-domains"))
3689 mono_dont_free_domains = TRUE;
3690 else if (!strcmp (option, "dyn-runtime-invoke"))
3691 mini_debug_options.dyn_runtime_invoke = TRUE;
3692 else if (!strcmp (option, "gdb"))
3693 mini_debug_options.gdb = TRUE;
3694 else if (!strcmp (option, "lldb"))
3695 mini_debug_options.lldb = TRUE;
3696 else if (!strcmp (option, "explicit-null-checks"))
3697 mini_debug_options.explicit_null_checks = TRUE;
3698 else if (!strcmp (option, "gen-seq-points"))
3699 mini_debug_options.gen_sdb_seq_points = TRUE;
3700 else if (!strcmp (option, "gen-compact-seq-points"))
3701 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3702 else if (!strcmp (option, "no-compact-seq-points"))
3703 mini_debug_options.no_seq_points_compact_data = TRUE;
3704 else if (!strcmp (option, "single-imm-size"))
3705 mini_debug_options.single_imm_size = TRUE;
3706 else if (!strcmp (option, "init-stacks"))
3707 mini_debug_options.init_stacks = TRUE;
3708 else if (!strcmp (option, "casts"))
3709 mini_debug_options.better_cast_details = TRUE;
3710 else if (!strcmp (option, "soft-breakpoints"))
3711 mini_debug_options.soft_breakpoints = TRUE;
3712 else if (!strcmp (option, "check-pinvoke-callconv"))
3713 mini_debug_options.check_pinvoke_callconv = TRUE;
3714 else if (!strcmp (option, "use-fallback-tls"))
3715 mini_debug_options.use_fallback_tls = TRUE;
3716 else if (!strcmp (option, "debug-domain-unload"))
3717 mono_enable_debug_domain_unload (TRUE);
3718 else if (!strcmp (option, "partial-sharing"))
3719 mono_set_partial_sharing_supported (TRUE);
3720 else if (!strcmp (option, "align-small-structs"))
3721 mono_align_small_structs = TRUE;
3722 else if (!strcmp (option, "native-debugger-break"))
3723 mini_debug_options.native_debugger_break = TRUE;
3724 else if (!strcmp (option, "disable_omit_fp"))
3725 mini_debug_options.disable_omit_fp = TRUE;
3726 // This is an internal testing feature.
3727 // Every tail. encountered is required to be optimized.
3728 // It is asserted.
3729 else if (!strcmp (option, "test-tailcall-require"))
3730 mini_debug_options.test_tailcall_require = TRUE;
3731 else if (!strcmp (option, "verbose-gdb"))
3732 mini_debug_options.verbose_gdb = TRUE;
3733 else if (!strncmp (option, "thread-dump-dir=", 16))
3734 mono_set_thread_dump_dir(g_strdup(option + 16));
3735 else if (!strncmp (option, "aot-skip=", 9)) {
3736 mini_debug_options.aot_skip_set = TRUE;
3737 mini_debug_options.aot_skip = atoi (option + 9);
3738 } else
3739 return FALSE;
3741 return TRUE;
3744 static void
3745 mini_parse_debug_options (void)
3747 char *options = g_getenv ("MONO_DEBUG");
3748 gchar **args, **ptr;
3750 if (!options)
3751 return;
3753 args = g_strsplit (options, ",", -1);
3754 g_free (options);
3756 for (ptr = args; ptr && *ptr; ptr++) {
3757 const char *arg = *ptr;
3759 if (!mini_parse_debug_option (arg)) {
3760 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3761 // test-tailcall-require is also accepted but not documented.
3762 // empty string is also accepted and ignored as a consequence
3763 // of appending ",foo" without checking for empty.
3764 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");
3765 exit (1);
3769 g_strfreev (args);
3772 MonoDebugOptions *
3773 mini_get_debug_options (void)
3775 return &mini_debug_options;
3778 static gpointer
3779 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3781 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3782 gpointer* desc = NULL;
3784 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3785 return desc;
3786 #if defined(__mono_ppc64__)
3787 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3789 desc [0] = addr;
3790 desc [1] = NULL;
3791 desc [2] = NULL;
3792 # endif
3793 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3794 return desc;
3795 #else
3796 return addr;
3797 #endif
3800 static gpointer
3801 mini_get_addr_from_ftnptr (gpointer descr)
3803 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3804 return *(gpointer*)descr;
3805 #else
3806 return descr;
3807 #endif
3810 static void
3811 register_jit_stats (void)
3813 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3814 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3815 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3816 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3817 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
3818 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3819 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3820 mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
3821 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3822 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3823 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3824 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3825 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3826 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3827 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3828 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3829 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3830 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3831 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3832 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3833 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3834 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3835 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3836 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3837 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3838 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3839 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3840 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3841 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3842 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3843 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3844 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3845 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3846 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3847 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3848 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3849 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3850 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3851 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3852 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3853 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3854 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3855 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3856 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3857 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3858 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3859 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3860 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3861 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3862 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3863 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3864 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3865 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3866 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3867 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3868 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3869 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3870 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3871 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3872 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3873 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3874 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3877 static void runtime_invoke_info_free (gpointer value);
3879 static gint
3880 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3882 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3883 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3885 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3888 static guint
3889 class_method_pair_hash (gconstpointer data)
3891 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3893 return (gsize)pair->klass ^ (gsize)pair->method;
3896 static void
3897 mini_create_jit_domain_info (MonoDomain *domain)
3899 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3901 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3902 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3903 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3904 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3905 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3906 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3907 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3908 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3909 mono_jit_code_hash_init (&info->interp_code_hash);
3911 domain->runtime_info = info;
3914 static void
3915 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3917 MonoJumpList *jlist = (MonoJumpList *)value;
3918 g_slist_free ((GSList*)jlist->list);
3921 static void
3922 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3924 GSList *list = (GSList *)value;
3925 g_slist_free (list);
3928 static void
3929 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3931 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3932 mono_code_manager_destroy (di->code_mp);
3933 g_free (di);
3936 static void
3937 runtime_invoke_info_free (gpointer value)
3939 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3941 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3942 if (info->dyn_call_info)
3943 mono_arch_dyn_call_free (info->dyn_call_info);
3944 #endif
3945 g_free (info);
3948 static void
3949 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3951 g_slist_free ((GSList*)value);
3954 static void
3955 mini_free_jit_domain_info (MonoDomain *domain)
3957 MonoJitDomainInfo *info = domain_jit_info (domain);
3959 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3960 g_hash_table_destroy (info->jump_target_hash);
3961 if (info->jump_target_got_slot_hash) {
3962 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3963 g_hash_table_destroy (info->jump_target_got_slot_hash);
3965 if (info->dynamic_code_hash) {
3966 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3967 g_hash_table_destroy (info->dynamic_code_hash);
3969 g_hash_table_destroy (info->method_code_hash);
3970 g_hash_table_destroy (info->jump_trampoline_hash);
3971 g_hash_table_destroy (info->jit_trampoline_hash);
3972 g_hash_table_destroy (info->delegate_trampoline_hash);
3973 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3974 g_hash_table_destroy (info->mrgctx_hash);
3975 g_hash_table_destroy (info->method_rgctx_hash);
3976 g_hash_table_destroy (info->interp_method_pointer_hash);
3977 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3978 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3979 g_hash_table_destroy (info->seq_points);
3980 g_hash_table_destroy (info->arch_seq_points);
3981 if (info->agent_info)
3982 mini_get_dbg_callbacks ()->free_domain_info (domain);
3983 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3984 if (info->llvm_jit_callees) {
3985 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3986 g_hash_table_destroy (info->llvm_jit_callees);
3988 mono_internal_hash_table_destroy (&info->interp_code_hash);
3989 #ifdef ENABLE_LLVM
3990 mono_llvm_free_domain_info (domain);
3991 #endif
3993 g_free (domain->runtime_info);
3994 domain->runtime_info = NULL;
3997 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3999 static void
4000 code_manager_chunk_new (void *chunk, int size)
4002 mono_arch_code_chunk_new (chunk, size);
4005 static void
4006 code_manager_chunk_destroy (void *chunk)
4008 mono_arch_code_chunk_destroy (chunk);
4011 #endif
4013 #ifdef ENABLE_LLVM
4014 static gboolean
4015 llvm_init_inner (void)
4017 if (!mono_llvm_load (NULL))
4018 return FALSE;
4020 mono_llvm_init ();
4021 return TRUE;
4023 #endif
4026 * mini_llvm_init:
4028 * Load and initialize LLVM support.
4029 * Return TRUE on success.
4031 gboolean
4032 mini_llvm_init (void)
4034 #ifdef ENABLE_LLVM
4035 static gboolean llvm_inited;
4036 static gboolean init_result;
4038 mono_loader_lock_if_inited ();
4039 if (!llvm_inited) {
4040 init_result = llvm_init_inner ();
4041 llvm_inited = TRUE;
4043 mono_loader_unlock_if_inited ();
4044 return init_result;
4045 #else
4046 return FALSE;
4047 #endif
4050 void
4051 mini_add_profiler_argument (const char *desc)
4053 if (!profile_options)
4054 profile_options = g_ptr_array_new ();
4056 g_ptr_array_add (profile_options, (gpointer) desc);
4060 static MonoEECallbacks interp_cbs = {0};
4062 void
4063 mini_install_interp_callbacks (MonoEECallbacks *cbs)
4065 memcpy (&interp_cbs, cbs, sizeof (MonoEECallbacks));
4068 MonoEECallbacks *
4069 mini_get_interp_callbacks (void)
4071 return &interp_cbs;
4074 static MonoDebuggerCallbacks dbg_cbs;
4076 void
4077 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4079 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4080 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4083 MonoDebuggerCallbacks*
4084 mini_get_dbg_callbacks (void)
4086 return &dbg_cbs;
4090 mono_ee_api_version (void)
4092 return MONO_EE_API_VERSION;
4095 void
4096 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4098 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4101 void
4102 mono_interp_to_native_trampoline (gpointer addr, gpointer ccontext)
4104 mini_get_interp_callbacks ()->to_native_trampoline (addr, ccontext);
4107 MonoDomain *
4108 mini_init (const char *filename, const char *runtime_version)
4110 ERROR_DECL (error);
4111 MonoDomain *domain;
4112 MonoRuntimeCallbacks callbacks;
4113 MonoThreadInfoRuntimeCallbacks ticallbacks;
4114 MonoCodeManagerCallbacks code_manager_callbacks;
4116 MONO_VES_INIT_BEGIN ();
4118 CHECKED_MONO_INIT ();
4120 #if defined(__linux__)
4121 if (access ("/proc/self/maps", F_OK) != 0) {
4122 g_print ("Mono requires /proc to be mounted.\n");
4123 exit (1);
4125 #endif
4127 mono_interp_stub_init ();
4128 #ifndef DISABLE_INTERPRETER
4129 if (mono_use_interpreter)
4130 mono_ee_interp_init (mono_interp_opts_string);
4131 #endif
4133 mono_debugger_agent_stub_init ();
4134 #ifndef DISABLE_SDB
4135 mono_debugger_agent_init ();
4136 #endif
4138 if (sdb_options)
4139 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4141 mono_os_mutex_init_recursive (&jit_mutex);
4143 mono_cross_helpers_run ();
4145 mono_counters_init ();
4147 mini_jit_init ();
4149 mini_jit_init_job_control ();
4151 /* Happens when using the embedding interface */
4152 if (!default_opt_set)
4153 default_opt = mono_parse_default_optimizations (NULL);
4155 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4156 if (mono_aot_only)
4157 mono_set_generic_sharing_vt_supported (TRUE);
4158 #else
4159 if (mono_llvm_only)
4160 mono_set_generic_sharing_vt_supported (TRUE);
4161 #endif
4163 mono_tls_init_runtime_keys ();
4165 if (!global_codeman)
4166 global_codeman = mono_code_manager_new ();
4168 memset (&callbacks, 0, sizeof (callbacks));
4169 callbacks.create_ftnptr = mini_create_ftnptr;
4170 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4171 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4172 callbacks.set_cast_details = mono_set_cast_details;
4173 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4174 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4175 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4176 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4177 callbacks.imt_entry_inited = mini_imt_entry_inited;
4178 callbacks.init_delegate = mini_init_delegate;
4179 #define JIT_INVOKE_WORKS
4180 #ifdef JIT_INVOKE_WORKS
4181 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4182 #endif
4183 #define JIT_TRAMPOLINES_WORK
4184 #ifdef JIT_TRAMPOLINES_WORK
4185 callbacks.compile_method = mono_jit_compile_method;
4186 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4187 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4188 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4189 callbacks.free_method = mono_jit_free_method;
4190 #ifndef DISABLE_REMOTING
4191 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4192 #endif
4193 #endif
4194 #ifndef DISABLE_REMOTING
4195 if (mono_use_interpreter)
4196 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4197 #endif
4198 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4200 #ifndef DISABLE_CRASH_REPORTING
4201 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4202 #endif
4204 mono_install_callbacks (&callbacks);
4206 memset (&ticallbacks, 0, sizeof (ticallbacks));
4207 ticallbacks.setup_async_callback = mono_setup_async_callback;
4208 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
4209 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
4210 ticallbacks.thread_state_init = mono_thread_state_init;
4212 #ifndef HOST_WIN32
4213 mono_w32handle_init ();
4214 #endif
4216 mono_thread_info_runtime_init (&ticallbacks);
4218 if (g_hasenv ("MONO_DEBUG")) {
4219 mini_parse_debug_options ();
4222 mono_code_manager_init ();
4224 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
4225 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4226 code_manager_callbacks.chunk_new = code_manager_chunk_new;
4227 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
4228 #endif
4229 mono_code_manager_install_callbacks (&code_manager_callbacks);
4231 mono_hwcap_init ();
4233 mono_arch_cpu_init ();
4235 mono_arch_init ();
4237 mono_unwind_init ();
4239 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
4240 mono_lldb_init ("");
4241 mono_dont_free_domains = TRUE;
4244 #ifdef XDEBUG_ENABLED
4245 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4246 if (mono_xdebug) {
4247 mono_xdebug_init (mono_xdebug);
4248 g_free (mono_xdebug);
4249 /* So methods for multiple domains don't have the same address */
4250 mono_dont_free_domains = TRUE;
4251 mono_using_xdebug = TRUE;
4252 } else if (mini_get_debug_options ()->gdb) {
4253 mono_xdebug_init ((char*)"gdb");
4254 mono_dont_free_domains = TRUE;
4255 mono_using_xdebug = TRUE;
4257 #endif
4259 #ifdef ENABLE_LLVM
4260 if (mono_use_llvm) {
4261 if (!mono_llvm_load (NULL)) {
4262 mono_use_llvm = FALSE;
4263 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4266 if (mono_use_llvm)
4267 mono_llvm_init ();
4268 #endif
4270 mono_trampolines_init ();
4272 if (default_opt & MONO_OPT_AOT)
4273 mono_aot_init ();
4275 mini_get_dbg_callbacks ()->init ();
4277 #ifdef TARGET_WASM
4278 mono_wasm_debugger_init ();
4279 #endif
4281 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4282 mono_set_generic_sharing_supported (TRUE);
4283 #endif
4285 mono_thread_info_signals_init ();
4287 #ifndef MONO_CROSS_COMPILE
4288 mono_runtime_install_handlers ();
4289 #endif
4290 mono_threads_install_cleanup (mini_thread_cleanup);
4292 #ifdef JIT_TRAMPOLINES_WORK
4293 mono_install_create_domain_hook (mini_create_jit_domain_info);
4294 mono_install_free_domain_hook (mini_free_jit_domain_info);
4295 #endif
4296 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4297 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4298 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4300 mono_profiler_state.context_enable = mini_profiler_context_enable;
4301 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4302 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4303 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4304 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4305 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4307 if (profile_options)
4308 for (guint i = 0; i < profile_options->len; i++)
4309 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4311 mono_profiler_started ();
4313 if (mini_debug_options.collect_pagefault_stats)
4314 mono_aot_set_make_unreadable (TRUE);
4316 if (runtime_version)
4317 domain = mono_init_version (filename, runtime_version);
4318 else
4319 domain = mono_init_from_assembly (filename, filename);
4321 if (mono_aot_only) {
4322 /* This helps catch code allocation requests */
4323 mono_code_manager_set_read_only (domain->code_mp);
4324 mono_marshal_use_aot_wrappers (TRUE);
4327 if (mono_llvm_only) {
4328 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline);
4329 mono_set_always_build_imt_trampolines (TRUE);
4330 } else if (mono_aot_only) {
4331 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4332 } else {
4333 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4336 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4337 mono_arch_finish_init ();
4339 /* This must come after mono_init () in the aot-only case */
4340 mono_exceptions_init ();
4342 /* This should come after mono_init () too */
4343 mini_gc_init ();
4345 #ifndef DISABLE_JIT
4346 mono_create_helper_signatures ();
4347 #endif
4349 register_jit_stats ();
4351 #define JIT_CALLS_WORK
4352 #ifdef JIT_CALLS_WORK
4353 /* Needs to be called here since register_jit_icall depends on it */
4354 mono_marshal_init ();
4356 mono_arch_register_lowlevel_calls ();
4358 register_icalls ();
4360 mono_generic_sharing_init ();
4361 #endif
4363 #ifdef MONO_ARCH_SIMD_INTRINSICS
4364 mono_simd_intrinsics_init ();
4365 #endif
4367 mono_tasklets_init ();
4369 register_trampolines (domain);
4371 if (mono_compile_aot)
4373 * Avoid running managed code when AOT compiling, since the platform
4374 * might only support aot-only execution.
4376 mono_runtime_set_no_exec (TRUE);
4378 mono_mem_account_register_counters ();
4380 #define JIT_RUNTIME_WORKS
4381 #ifdef JIT_RUNTIME_WORKS
4382 #ifndef DISABLE_CLEANUP
4383 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4384 #endif
4385 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4386 mono_error_assert_ok (error);
4387 mono_thread_attach (domain);
4388 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4389 #endif
4391 if (mono_profiler_sampling_enabled ())
4392 mono_runtime_setup_stat_profiler ();
4394 MONO_PROFILER_RAISE (runtime_initialized, ());
4396 MONO_VES_INIT_END ();
4398 return domain;
4401 #ifdef MONO_ARCH_EMULATE_FREM
4402 // Wrapper to avoid taking address of overloaded function.
4403 static double
4404 mono_fmod (double a, double b)
4406 return fmod (a, b);
4408 #endif
4410 static void
4411 register_icalls (void)
4413 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4414 ves_icall_get_frame_info);
4415 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4416 ves_icall_get_trace);
4417 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4418 mono_runtime_install_handlers);
4419 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4420 mono_runtime_cleanup_handlers);
4422 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4423 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4424 mini_get_dbg_callbacks ()->unhandled_exception);
4425 #endif
4428 * It's important that we pass `TRUE` as the last argument here, as
4429 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4430 * *did* emit a wrapper, we'd be looking at infinite recursion since
4431 * the wrapper would call the icall which would call the wrapper and
4432 * so on.
4434 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4435 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4436 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4437 register_icall (mono_profiler_raise_exception_clause, "mono_profiler_raise_exception_clause", "void ptr int int object", TRUE);
4439 register_icall (mono_trace_enter_method, "mono_trace_enter_method", "void ptr ptr", TRUE);
4440 register_icall (mono_trace_leave_method, "mono_trace_leave_method", "void ptr ptr", TRUE);
4441 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4442 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4443 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4445 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4446 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4447 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4448 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int ptr object", TRUE);
4449 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4450 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4451 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4452 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4453 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4455 // FIXME: This is broken
4456 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4457 #endif
4459 if (!mono_llvm_only) {
4460 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4461 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4462 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4464 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4465 register_icall (ves_icall_thread_finish_async_abort, "ves_icall_thread_finish_async_abort", "void", FALSE);
4466 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4467 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4469 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4471 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4472 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4473 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4474 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4475 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4476 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4477 #endif
4478 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4479 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4480 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4481 #endif
4483 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4484 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4485 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4486 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4487 #endif
4489 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4490 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4491 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4492 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4493 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4494 #endif
4496 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4497 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4498 #endif
4500 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4501 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4502 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4503 #endif
4505 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4506 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4507 #endif
4509 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8_2, "mono_fconv_u8_2", FALSE);
4510 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4511 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4_2, "mono_fconv_u4_2", FALSE);
4512 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4513 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4514 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4515 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4518 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4519 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4520 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4521 #endif
4523 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4524 register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);
4525 #endif
4526 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4527 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4528 #endif
4529 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4530 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4531 #endif
4532 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4533 register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
4534 #endif
4535 #ifdef MONO_ARCH_EMULATE_FREM
4536 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "fmod", FALSE);
4537 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4538 #endif
4540 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4541 if (mono_arch_is_soft_float ()) {
4542 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4543 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4544 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4545 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4546 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4547 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4548 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4549 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4550 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4551 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4552 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4553 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4555 #if TARGET_SIZEOF_VOID_P == 4
4556 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4557 #endif
4559 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4560 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4561 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4562 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4563 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4564 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4565 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4566 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4567 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4568 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4570 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4571 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4572 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4573 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4574 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4576 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4577 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4578 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4579 register_icall (mono_isfinite_double, "mono_isfinite_double", "int32 double", FALSE);
4581 #endif
4582 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4584 #ifdef COMPRESSED_INTERFACE_BITMAP
4585 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4586 #endif
4588 #if SIZEOF_REGISTER == 4
4589 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4590 #else
4591 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4592 #endif
4594 /* other jit icalls */
4595 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4596 register_icall (ves_icall_mono_delegate_ctor_interp, "ves_icall_mono_delegate_ctor_interp", "void object object ptr", FALSE);
4597 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4598 "ptr ptr ptr", FALSE);
4599 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4600 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4601 "ptr ptr ptr ptr", FALSE);
4602 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4603 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4604 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4605 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4606 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4607 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4608 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4609 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4610 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4611 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4612 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4613 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4614 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4615 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4616 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4617 register_icall (mono_value_copy_internal, "mono_value_copy_internal", "void ptr ptr ptr", FALSE);
4618 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4619 register_icall (mono_break, "mono_break", NULL, TRUE);
4620 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4621 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4622 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4623 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4624 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4625 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4626 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4627 register_icall (mono_array_new_n_icall, "mono_array_new_n_icall", "object ptr int ptr", FALSE);
4628 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4629 register_icall (mono_resume_unwind, "mono_resume_unwind", "void ptr", TRUE);
4630 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4631 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4633 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4634 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4636 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4637 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4638 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4639 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4640 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4642 register_dyn_icall (mini_get_dbg_callbacks ()->user_break, "mono_debugger_agent_user_break", "void", FALSE);
4644 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4645 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4646 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4647 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4649 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, "mini_llvmonly_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4650 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, "mini_llvmonly_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4651 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call, "mini_llvmonly_resolve_generic_virtual_call", "ptr ptr int ptr");
4652 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call, "mini_llvmonly_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4653 /* This needs a wrapper so it can have a preserveall cconv */
4654 register_icall (mini_llvmonly_init_vtable_slot, "mini_llvmonly_init_vtable_slot", "ptr ptr int", FALSE);
4655 register_icall (mini_llvmonly_init_delegate, "mini_llvmonly_init_delegate", "void object", TRUE);
4656 register_icall (mini_llvmonly_init_delegate_virtual, "mini_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4658 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4659 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4660 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4661 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4663 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "int32 obj");
4664 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4665 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4666 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4668 #ifdef TARGET_IOS
4669 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4670 #endif
4671 /* Register tls icalls */
4672 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4673 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4674 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4675 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4676 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4677 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4678 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4679 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4680 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4681 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4683 register_icall_no_wrapper (mono_interp_entry_from_trampoline, "mono_interp_entry_from_trampoline", "void ptr ptr");
4684 register_icall_no_wrapper (mono_interp_to_native_trampoline, "mono_interp_to_native_trampoline", "void ptr ptr");
4686 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4687 mono_arch_register_icall ();
4688 #endif
4691 MonoJitStats mono_jit_stats = {0};
4694 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4695 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4697 MONO_NO_SANITIZE_THREAD
4698 static void
4699 print_jit_stats (void)
4701 if (mono_jit_stats.enabled) {
4702 g_print ("Mono Jit statistics\n");
4703 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4704 mono_jit_stats.max_ratio_method);
4705 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4706 mono_jit_stats.biggest_method);
4708 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4709 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4710 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4711 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4712 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4713 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4714 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4715 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4717 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4718 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4719 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4721 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4722 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4723 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4724 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4726 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4727 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4728 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4729 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4730 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4731 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4732 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4733 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4735 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4736 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4737 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4739 g_free (mono_jit_stats.max_ratio_method);
4740 mono_jit_stats.max_ratio_method = NULL;
4741 g_free (mono_jit_stats.biggest_method);
4742 mono_jit_stats.biggest_method = NULL;
4746 void
4747 mini_cleanup (MonoDomain *domain)
4749 if (mono_profiler_sampling_enabled ())
4750 mono_runtime_shutdown_stat_profiler ();
4752 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4754 #ifndef DISABLE_COM
4755 mono_cominterop_release_all_rcws ();
4756 #endif
4758 #ifndef MONO_CROSS_COMPILE
4760 * mono_domain_finalize () needs to be called early since it needs the
4761 * execution engine still fully working (it may invoke managed finalizers).
4763 mono_domain_finalize (domain, 2000);
4764 #endif
4766 /* This accesses metadata so needs to be called before runtime shutdown */
4767 print_jit_stats ();
4769 #ifndef MONO_CROSS_COMPILE
4770 mono_runtime_cleanup (domain);
4771 #endif
4773 mono_threadpool_cleanup ();
4775 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4777 mono_profiler_cleanup ();
4779 if (profile_options)
4780 g_ptr_array_free (profile_options, TRUE);
4782 free_jit_tls_data (mono_tls_get_jit_tls ());
4784 mono_icall_cleanup ();
4786 mono_runtime_cleanup_handlers ();
4788 #ifndef MONO_CROSS_COMPILE
4789 mono_domain_free (domain, TRUE);
4790 #endif
4792 #ifdef ENABLE_LLVM
4793 if (mono_use_llvm)
4794 mono_llvm_cleanup ();
4795 #endif
4797 mono_aot_cleanup ();
4799 mono_trampolines_cleanup ();
4801 mono_unwind_cleanup ();
4803 mono_code_manager_destroy (global_codeman);
4804 g_free (vtable_trampolines);
4806 mini_jit_cleanup ();
4808 mono_tramp_info_cleanup ();
4810 mono_arch_cleanup ();
4812 mono_generic_sharing_cleanup ();
4814 mono_cleanup ();
4816 mono_trace_cleanup ();
4818 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4820 if (mono_inject_async_exc_method)
4821 mono_method_desc_free (mono_inject_async_exc_method);
4823 mono_tls_free_keys ();
4825 mono_os_mutex_destroy (&jit_mutex);
4827 mono_code_manager_cleanup ();
4829 #ifndef HOST_WIN32
4830 mono_w32handle_cleanup ();
4831 #endif
4834 void
4835 mono_set_defaults (int verbose_level, guint32 opts)
4837 mini_verbose = verbose_level;
4838 mono_set_optimizations (opts);
4841 void
4842 mono_disable_optimizations (guint32 opts)
4844 default_opt &= ~opts;
4847 void
4848 mono_set_optimizations (guint32 opts)
4850 default_opt = opts;
4851 default_opt_set = TRUE;
4852 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4853 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4854 #else
4855 if (mono_llvm_only)
4856 mono_set_generic_sharing_vt_supported (TRUE);
4857 #endif
4860 void
4861 mono_set_verbose_level (guint32 level)
4863 mini_verbose = level;
4867 * mono_get_runtime_build_info:
4868 * The returned string is owned by the caller. The returned string
4869 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4870 * \returns the runtime version + build date in string format.
4872 char*
4873 mono_get_runtime_build_info (void)
4875 if (mono_build_date)
4876 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4877 else
4878 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4881 static void
4882 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4884 GHashTable *assemblies = (GHashTable*)user_data;
4885 MonoImage *image = mono_assembly_get_image_internal (ass);
4886 MonoMethod *method, *invoke;
4887 int i, count = 0;
4889 if (g_hash_table_lookup (assemblies, ass))
4890 return;
4892 g_hash_table_insert (assemblies, ass, ass);
4894 if (mini_verbose > 0)
4895 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4897 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4898 ERROR_DECL (error);
4900 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
4901 if (!method) {
4902 mono_error_cleanup (error); /* FIXME don't swallow the error */
4903 continue;
4905 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4906 continue;
4907 if (method->is_generic || mono_class_is_gtd (method->klass))
4908 continue;
4910 count++;
4911 if (mini_verbose > 1) {
4912 char * desc = mono_method_full_name (method, TRUE);
4913 g_print ("Compiling %d %s\n", count, desc);
4914 g_free (desc);
4916 mono_compile_method_checked (method, error);
4917 if (!is_ok (error)) {
4918 mono_error_cleanup (error); /* FIXME don't swallow the error */
4919 continue;
4921 if (strcmp (method->name, "Finalize") == 0) {
4922 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4923 mono_compile_method_checked (invoke, error);
4924 mono_error_assert_ok (error);
4926 #ifndef DISABLE_REMOTING
4927 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
4928 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
4929 mono_error_assert_ok (error);
4930 mono_compile_method_checked (invoke, error);
4931 mono_error_assert_ok (error);
4933 #endif
4936 /* Load and precompile referenced assemblies as well */
4937 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4938 mono_assembly_load_reference (image, i);
4939 if (image->references [i])
4940 mono_precompile_assembly (image->references [i], assemblies);
4944 void mono_precompile_assemblies ()
4946 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4948 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4950 g_hash_table_destroy (assemblies);
4954 * Used by LLVM.
4955 * Have to export this for AOT.
4957 void
4958 mono_personality (void)
4960 /* Not used */
4961 g_assert_not_reached ();
4964 static MonoBreakPolicy
4965 always_insert_breakpoint (MonoMethod *method)
4967 return MONO_BREAK_POLICY_ALWAYS;
4970 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4973 * mono_set_break_policy:
4974 * \param policy_callback the new callback function
4976 * Allow embedders to decide whether to actually obey breakpoint instructions
4977 * (both break IL instructions and \c Debugger.Break method calls), for example
4978 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4979 * untrusted or semi-trusted code.
4981 * \p policy_callback will be called every time a break point instruction needs to
4982 * be inserted with the method argument being the method that calls \c Debugger.Break
4983 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4984 * if it wants the breakpoint to not be effective in the given method.
4985 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4987 void
4988 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4990 if (policy_callback)
4991 break_policy_func = policy_callback;
4992 else
4993 break_policy_func = always_insert_breakpoint;
4996 gboolean
4997 mini_should_insert_breakpoint (MonoMethod *method)
4999 switch (break_policy_func (method)) {
5000 case MONO_BREAK_POLICY_ALWAYS:
5001 return TRUE;
5002 case MONO_BREAK_POLICY_NEVER:
5003 return FALSE;
5004 case MONO_BREAK_POLICY_ON_DBG:
5005 g_warning ("mdb no longer supported");
5006 return FALSE;
5007 default:
5008 g_warning ("Incorrect value returned from break policy callback");
5009 return FALSE;
5013 // Custom handlers currently only implemented by Windows.
5014 #ifndef HOST_WIN32
5015 gboolean
5016 mono_runtime_install_custom_handlers (const char *handlers)
5018 return FALSE;
5021 void
5022 mono_runtime_install_custom_handlers_usage (void)
5024 fprintf (stdout,
5025 "Custom Handlers:\n"
5026 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5027 " separated list of available handlers to install.\n"
5028 "\n"
5029 "No handlers supported on current platform.\n");
5031 #endif /* HOST_WIN32 */