[interp] Fix fullaotinterp exceptions (#11760)
[mono-project.git] / mono / mini / mini-runtime.c
blob7800a0ca1e5f8689a64f0fd0e682896a4bd877d7
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"
85 #include "jit-icalls.h"
87 #include "mini-gc.h"
88 #include "mini-llvm.h"
89 #include "debugger-agent.h"
90 #include "lldb.h"
91 #include "mini-runtime.h"
92 #include "interp/interp.h"
94 #ifdef MONO_ARCH_LLVM_SUPPORTED
95 #ifdef ENABLE_LLVM
96 #include "mini-llvm-cpp.h"
97 #include "llvm-jit.h"
98 #endif
99 #endif
101 static guint32 default_opt = 0;
102 static gboolean default_opt_set = FALSE;
104 gboolean mono_compile_aot = FALSE;
105 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
106 gboolean mono_aot_only = FALSE;
107 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
108 gboolean mono_llvm_only = FALSE;
109 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NONE;
110 MonoEEFeatures mono_ee_features;
112 const char *mono_build_date;
113 gboolean mono_do_signal_chaining;
114 gboolean mono_do_crash_chaining;
115 int mini_verbose = 0;
118 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
119 * it can load AOT code compiled by LLVM.
121 gboolean mono_use_llvm = FALSE;
123 gboolean mono_use_interpreter = FALSE;
124 const char *mono_interp_opts_string = NULL;
126 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
127 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
128 static mono_mutex_t jit_mutex;
130 static MonoCodeManager *global_codeman;
132 MonoDebugOptions mini_debug_options;
133 char *sdb_options;
135 #ifdef VALGRIND_JIT_REGISTER_MAP
136 int valgrind_register;
137 #endif
138 GList* mono_aot_paths;
140 static GPtrArray *profile_options;
142 static GSList *tramp_infos;
143 GSList *mono_interp_only_classes;
145 static void register_icalls (void);
147 gboolean
148 mono_running_on_valgrind (void)
150 #ifndef HOST_WIN32
151 if (RUNNING_ON_VALGRIND){
152 #ifdef VALGRIND_JIT_REGISTER_MAP
153 valgrind_register = TRUE;
154 #endif
155 return TRUE;
156 } else
157 #endif
158 return FALSE;
161 typedef struct {
162 void *ip;
163 MonoMethod *method;
164 } FindTrampUserData;
166 static void
167 find_tramp (gpointer key, gpointer value, gpointer user_data)
169 FindTrampUserData *ud = (FindTrampUserData*)user_data;
171 if (value == ud->ip)
172 ud->method = (MonoMethod*)key;
175 /* debug function */
176 G_GNUC_UNUSED static char*
177 get_method_from_ip (void *ip)
179 MonoJitInfo *ji;
180 MonoMethod *method;
181 char *method_name;
182 char *res;
183 MonoDomain *domain = mono_domain_get ();
184 MonoDebugSourceLocation *location;
185 FindTrampUserData user_data;
187 if (!domain)
188 domain = mono_get_root_domain ();
190 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
191 if (!ji) {
192 user_data.ip = ip;
193 user_data.method = NULL;
194 mono_domain_lock (domain);
195 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
196 mono_domain_unlock (domain);
197 if (user_data.method) {
198 char *mname = mono_method_full_name (user_data.method, TRUE);
199 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
200 g_free (mname);
201 return res;
203 else
204 return NULL;
205 } else if (ji->is_trampoline) {
206 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
207 return res;
210 method = jinfo_get_method (ji);
211 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
212 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
214 char *file_loc = NULL;
215 if (location)
216 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
218 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);
220 mono_debug_free_source_location (location);
221 g_free (method_name);
222 g_free (file_loc);
224 return res;
228 * mono_pmip:
229 * \param ip an instruction pointer address
231 * This method is used from a debugger to get the name of the
232 * method at address \p ip. This routine is typically invoked from
233 * a debugger like this:
235 * (gdb) print mono_pmip ($pc)
237 * \returns the name of the method at address \p ip.
239 G_GNUC_UNUSED char *
240 mono_pmip (void *ip)
242 return get_method_from_ip (ip);
246 * mono_print_method_from_ip:
247 * \param ip an instruction pointer address
249 * This method is used from a debugger to get the name of the
250 * method at address \p ip.
252 * This prints the name of the method at address \p ip in the standard
253 * output. Unlike \c mono_pmip which returns a string, this routine
254 * prints the value on the standard output.
256 MONO_ATTR_USED void
257 mono_print_method_from_ip (void *ip)
259 MonoJitInfo *ji;
260 char *method;
261 MonoDebugSourceLocation *source;
262 MonoDomain *domain = mono_domain_get ();
263 MonoDomain *target_domain = mono_domain_get ();
264 FindTrampUserData user_data;
265 MonoGenericSharingContext*gsctx;
266 const char *shared_type;
268 if (!domain)
269 domain = mono_get_root_domain ();
270 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
271 if (ji && ji->is_trampoline) {
272 MonoTrampInfo *tinfo = ji->d.tramp_info;
274 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
275 return;
278 if (!ji) {
279 user_data.ip = ip;
280 user_data.method = NULL;
281 mono_domain_lock (domain);
282 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
283 mono_domain_unlock (domain);
285 if (user_data.method) {
286 char *mname = mono_method_full_name (user_data.method, TRUE);
287 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
288 g_free (mname);
289 return;
292 g_print ("No method at %p\n", ip);
293 fflush (stdout);
294 return;
296 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
297 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
299 gsctx = mono_jit_info_get_generic_sharing_context (ji);
300 shared_type = "";
301 if (gsctx) {
302 if (gsctx->is_gsharedvt)
303 shared_type = "gsharedvt ";
304 else
305 shared_type = "gshared ";
308 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);
310 if (source)
311 g_print ("%s:%d\n", source->source_file, source->row);
312 fflush (stdout);
314 mono_debug_free_source_location (source);
315 g_free (method);
319 * mono_method_same_domain:
321 * Determine whenever two compiled methods are in the same domain, thus
322 * the address of the callee can be embedded in the caller.
324 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
326 MonoMethod *cmethod;
328 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
329 return FALSE;
332 * If the call was made from domain-neutral to domain-specific
333 * code, we can't patch the call site.
335 if (caller->domain_neutral && !callee->domain_neutral)
336 return FALSE;
338 cmethod = jinfo_get_method (caller);
339 if ((cmethod->klass == mono_defaults.appdomain_class) &&
340 (strstr (cmethod->name, "InvokeInDomain"))) {
341 /* The InvokeInDomain methods change the current appdomain */
342 return FALSE;
345 return TRUE;
349 * mono_global_codeman_reserve:
351 * Allocate code memory from the global code manager.
353 void *(mono_global_codeman_reserve) (int size)
355 void *ptr;
357 if (mono_aot_only)
358 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
360 if (!global_codeman) {
361 /* This can happen during startup */
362 global_codeman = mono_code_manager_new ();
363 return mono_code_manager_reserve (global_codeman, size);
365 else {
366 mono_jit_lock ();
367 ptr = mono_code_manager_reserve (global_codeman, size);
368 mono_jit_unlock ();
369 return ptr;
373 /* The callback shouldn't take any locks */
374 void
375 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
377 mono_jit_lock ();
378 mono_code_manager_foreach (global_codeman, func, user_data);
379 mono_jit_unlock ();
383 * mono_create_unwind_op:
385 * Create an unwind op with the given parameters.
387 MonoUnwindOp*
388 mono_create_unwind_op (int when, int tag, int reg, int val)
390 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
392 op->op = tag;
393 op->reg = reg;
394 op->val = val;
395 op->when = when;
397 return op;
400 MonoJumpInfoToken *
401 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
403 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
404 res->image = image;
405 res->token = token;
406 res->has_context = context != NULL;
407 if (context)
408 memcpy (&res->context, context, sizeof (MonoGenericContext));
410 return res;
413 MonoJumpInfoToken *
414 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
416 return mono_jump_info_token_new2 (mp, image, token, NULL);
420 * mono_tramp_info_create:
422 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
423 * of JI, and UNWIND_OPS.
425 MonoTrampInfo*
426 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
428 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
430 info->name = g_strdup (name);
431 info->code = code;
432 info->code_size = code_size;
433 info->ji = ji;
434 info->unwind_ops = unwind_ops;
436 return info;
439 void
440 mono_tramp_info_free (MonoTrampInfo *info)
442 g_free (info->name);
444 // FIXME: ji
445 mono_free_unwind_info (info->unwind_ops);
446 if (info->owns_uw_info)
447 g_free (info->uw_info);
448 g_free (info);
451 static void
452 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
454 MonoJitInfo *ji;
456 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
457 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
458 ji->d.tramp_info = info;
459 ji->is_trampoline = TRUE;
461 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
463 mono_jit_info_table_add (domain, ji);
467 * mono_tramp_info_register:
469 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
470 * INFO can be NULL.
471 * Frees INFO.
473 static void
474 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
476 MonoTrampInfo *copy;
478 if (!info)
479 return;
481 if (!domain)
482 domain = mono_get_root_domain ();
484 if (domain)
485 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
486 else
487 copy = g_new0 (MonoTrampInfo, 1);
489 copy->code = info->code;
490 copy->code_size = info->code_size;
491 copy->name = g_strdup (info->name);
493 if (info->unwind_ops) {
494 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
495 copy->owns_uw_info = TRUE;
496 if (domain) {
497 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
498 guint8 *temp = copy->uw_info;
499 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
500 memcpy (copy->uw_info, temp, copy->uw_info_len);
501 g_free (temp);
503 } else {
504 /* Trampolines from aot have the unwind ops already encoded */
505 copy->uw_info = info->uw_info;
506 copy->uw_info_len = info->uw_info_len;
509 mono_save_trampoline_xdebug_info (info);
510 mono_lldb_save_trampoline_info (info);
512 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
513 if (!aot)
514 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
515 #endif
517 if (!domain) {
518 /* If no root domain has been created yet, postpone the registration. */
519 mono_jit_lock ();
520 tramp_infos = g_slist_prepend (tramp_infos, copy);
521 mono_jit_unlock ();
522 } else if (copy->uw_info) {
523 /* Only register trampolines that have unwind infos */
524 register_trampoline_jit_info (domain, copy);
527 if (mono_jit_map_is_enabled ())
528 mono_emit_jit_tramp (info->code, info->code_size, info->name);
530 mono_tramp_info_free (info);
533 void
534 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
536 mono_tramp_info_register_internal (info, domain, FALSE);
539 void
540 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
542 mono_tramp_info_register_internal (info, domain, TRUE);
545 static void
546 mono_tramp_info_cleanup (void)
548 GSList *l;
550 for (l = tramp_infos; l; l = l->next) {
551 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
553 mono_tramp_info_free (info);
555 g_slist_free (tramp_infos);
558 /* Register trampolines created before the root domain was created in the jit info tables */
559 static void
560 register_trampolines (MonoDomain *domain)
562 GSList *l;
564 for (l = tramp_infos; l; l = l->next) {
565 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
567 register_trampoline_jit_info (domain, info);
571 G_GNUC_UNUSED static void
572 break_count (void)
577 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
578 * Set a breakpoint in break_count () to break the last time <x> is done.
580 G_GNUC_UNUSED gboolean
581 mono_debug_count (void)
583 static int count = 0, int_val = 0;
584 static gboolean inited, has_value = FALSE;
586 count ++;
588 if (!inited) {
589 char *value = g_getenv ("COUNT");
590 if (value) {
591 int_val = atoi (value);
592 g_free (value);
593 has_value = TRUE;
595 inited = TRUE;
598 if (!has_value)
599 return TRUE;
601 if (count == int_val)
602 break_count ();
604 if (count > int_val)
605 return FALSE;
607 return TRUE;
610 MonoMethod*
611 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
613 MonoMethod *wrapper;
614 gboolean check_exc = TRUE;
615 char *name;
617 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
618 /* This icall is used to check for exceptions, so don't check in the wrapper */
619 check_exc = FALSE;
621 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
622 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
623 g_free (name);
625 return wrapper;
628 gconstpointer
629 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
631 ERROR_DECL (error);
632 MonoMethod *wrapper;
633 gconstpointer trampoline;
634 MonoDomain *domain = mono_get_root_domain ();
636 if (callinfo->wrapper)
637 return callinfo->wrapper;
639 if (callinfo->trampoline)
640 return callinfo->trampoline;
642 wrapper = mono_icall_get_wrapper_method (callinfo);
644 if (do_compile) {
645 trampoline = mono_compile_method_checked (wrapper, error);
646 mono_error_assert_ok (error);
647 } else {
648 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
649 mono_error_assert_ok (error);
650 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
653 mono_loader_lock ();
654 if (!callinfo->trampoline) {
655 mono_register_jit_icall_wrapper (callinfo, trampoline);
656 callinfo->trampoline = trampoline;
658 mono_loader_unlock ();
660 return callinfo->trampoline;
663 gconstpointer
664 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
666 return mono_icall_get_wrapper_full (callinfo, FALSE);
669 static MonoJitDynamicMethodInfo*
670 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
672 MonoJitDynamicMethodInfo *res;
674 if (domain_jit_info (domain)->dynamic_code_hash)
675 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
676 else
677 res = NULL;
678 return res;
681 #ifdef __cplusplus
682 template <typename T>
683 static void
684 register_opcode_emulation (int opcode, const char *name, const char *sigstr, T func, const char *symbol, gboolean no_wrapper)
685 #else
686 static void
687 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_wrapper)
688 #endif
690 #ifndef DISABLE_JIT
691 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_wrapper);
692 #else
693 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
695 g_assert (!sig->hasthis);
696 g_assert (sig->param_count < 3);
698 mono_register_jit_icall_full (func, name, sig, no_wrapper, symbol);
699 #endif
703 * For JIT icalls implemented in C.
704 * NAME should be the same as the name of the C function whose address is FUNC.
705 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
706 * can't throw exceptions.
708 #ifdef __cplusplus
709 template <typename T>
710 static void
711 register_icall (T func, const char *name, const char *sigstr, gboolean avoid_wrapper)
712 #else
713 static void
714 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
715 #endif
717 MonoMethodSignature *sig;
719 if (sigstr)
720 sig = mono_create_icall_signature (sigstr);
721 else
722 sig = NULL;
724 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, avoid_wrapper ? name : NULL);
727 #ifdef __cplusplus
728 template <typename T>
729 static void
730 register_icall_no_wrapper (T func, const char *name, const char *sigstr)
731 #else
732 static void
733 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
734 #endif
736 MonoMethodSignature *sig;
738 if (sigstr)
739 sig = mono_create_icall_signature (sigstr);
740 else
741 sig = NULL;
743 mono_register_jit_icall_full (func, name, sig, TRUE, name);
746 #ifdef __cplusplus
747 template <typename T>
748 static void
749 register_icall_with_wrapper (T func, const char *name, const char *sigstr)
750 #else
751 static void
752 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
753 #endif
755 MonoMethodSignature *sig;
757 if (sigstr)
758 sig = mono_create_icall_signature (sigstr);
759 else
760 sig = NULL;
762 mono_register_jit_icall_full (func, name, sig, FALSE, NULL);
765 static void
766 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
768 MonoMethodSignature *sig;
770 if (sigstr)
771 sig = mono_create_icall_signature (sigstr);
772 else
773 sig = NULL;
775 mono_register_jit_icall (func, name, sig, save);
778 MonoLMF *
779 mono_get_lmf (void)
781 MonoJitTlsData *jit_tls;
783 if ((jit_tls = mono_tls_get_jit_tls ()))
784 return jit_tls->lmf;
786 * We do not assert here because this function can be called from
787 * mini-gc.c on a thread that has not executed any managed code, yet
788 * (the thread object allocation can trigger a collection).
790 return NULL;
793 void
794 mono_set_lmf (MonoLMF *lmf)
796 (*mono_get_lmf_addr ()) = lmf;
799 static void
800 mono_set_jit_tls (MonoJitTlsData *jit_tls)
802 MonoThreadInfo *info;
804 mono_tls_set_jit_tls (jit_tls);
806 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
807 info = mono_thread_info_current ();
808 if (info)
809 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
812 static void
813 mono_set_lmf_addr (MonoLMF **lmf_addr)
815 MonoThreadInfo *info;
817 mono_tls_set_lmf_addr (lmf_addr);
819 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
820 info = mono_thread_info_current ();
821 if (info)
822 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
826 * mono_push_lmf:
828 * Push an MonoLMFExt frame on the LMF stack.
830 void
831 mono_push_lmf (MonoLMFExt *ext)
833 MonoLMF **lmf_addr;
835 lmf_addr = mono_get_lmf_addr ();
837 ext->lmf.previous_lmf = *lmf_addr;
838 /* Mark that this is a MonoLMFExt */
839 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
841 mono_set_lmf ((MonoLMF*)ext);
845 * mono_pop_lmf:
847 * Pop the last frame from the LMF stack.
849 void
850 mono_pop_lmf (MonoLMF *lmf)
852 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
856 * mono_jit_thread_attach:
858 * Called by Xamarin.Mac and other products. Attach thread to runtime if
859 * needed and switch to @domain.
861 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
863 * If the thread is newly-attached, put into GC Safe mode.
865 * @return the original domain which needs to be restored, or NULL.
867 MonoDomain*
868 mono_jit_thread_attach (MonoDomain *domain)
870 MonoDomain *orig;
871 gboolean attached;
873 if (!domain) {
874 /* Happens when called from AOTed code which is only used in the root domain. */
875 domain = mono_get_root_domain ();
878 g_assert (domain);
880 attached = mono_tls_get_jit_tls () != NULL;
882 if (!attached) {
883 mono_thread_attach (domain);
885 // #678164
886 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
888 /* mono_jit_thread_attach is external-only and not called by
889 * the runtime on any of our own threads. So if we get here,
890 * the thread is running native code - leave it in GC Safe mode
891 * and leave it to the n2m invoke wrappers or MONO_API entry
892 * points to switch to GC Unsafe.
894 MONO_STACKDATA (stackdata);
895 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
898 orig = mono_domain_get ();
899 if (orig != domain)
900 mono_domain_set (domain, TRUE);
902 return orig != domain ? orig : NULL;
906 * mono_jit_set_domain:
908 * Set domain to @domain if @domain is not null
910 void
911 mono_jit_set_domain (MonoDomain *domain)
913 g_assert (!mono_threads_is_blocking_transition_enabled ());
915 if (domain)
916 mono_domain_set (domain, TRUE);
920 * mono_thread_abort:
921 * \param obj exception object
922 * Abort the thread, print exception information and stack trace
924 static void
925 mono_thread_abort (MonoObject *obj)
927 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
929 /* handle_remove should be eventually called for this thread, too
930 g_free (jit_tls);*/
932 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
933 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
934 ((obj->vtable->klass) == mono_class_get_appdomain_unloaded_exception_class () &&
935 mono_thread_info_current ()->runtime_thread)) {
936 mono_thread_exit ();
937 } else {
938 mono_invoke_unhandled_exception_hook (obj);
942 static MonoJitTlsData*
943 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
945 MonoJitTlsData *jit_tls;
946 MonoLMF *lmf;
948 jit_tls = mono_tls_get_jit_tls ();
949 if (jit_tls)
950 return jit_tls;
952 jit_tls = g_new0 (MonoJitTlsData, 1);
954 jit_tls->abort_func = abort_func;
955 jit_tls->end_of_stack = stack_start;
957 mono_set_jit_tls (jit_tls);
959 lmf = g_new0 (MonoLMF, 1);
960 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
962 jit_tls->first_lmf = lmf;
964 mono_set_lmf_addr (&jit_tls->lmf);
966 jit_tls->lmf = lmf;
968 #ifdef MONO_ARCH_HAVE_TLS_INIT
969 mono_arch_tls_init ();
970 #endif
972 mono_setup_altstack (jit_tls);
974 return jit_tls;
977 static void
978 free_jit_tls_data (MonoJitTlsData *jit_tls)
980 //This happens during AOT cuz the thread is never attached
981 if (!jit_tls)
982 return;
983 mono_arch_free_jit_tls_data (jit_tls);
984 mono_free_altstack (jit_tls);
986 g_free (jit_tls->first_lmf);
987 g_free (jit_tls->interp_context);
988 g_free (jit_tls);
991 static void
992 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
994 MonoThreadInfo *thread;
995 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
996 thread = mono_thread_info_current_unchecked ();
997 if (thread)
998 thread->jit_data = jit_tls;
1000 mono_arch_cpu_init ();
1003 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
1005 static void
1006 mono_thread_abort_dummy (MonoObject *obj)
1008 if (mono_thread_attach_aborted_cb)
1009 mono_thread_attach_aborted_cb (obj);
1010 else
1011 mono_thread_abort (obj);
1014 static void
1015 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
1017 MonoThreadInfo *thread;
1018 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
1019 thread = mono_thread_info_current_unchecked ();
1020 if (thread)
1021 thread->jit_data = jit_tls;
1023 mono_arch_cpu_init ();
1026 static void
1027 mini_thread_cleanup (MonoNativeThreadId tid)
1029 MonoJitTlsData *jit_tls = NULL;
1030 MonoThreadInfo *info;
1032 info = mono_thread_info_current_unchecked ();
1034 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1035 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1036 * not a trivial thing.
1038 * The current offender is mono_thread_manage which cleanup threads from the outside.
1040 if (info && mono_thread_info_get_tid (info) == tid) {
1041 jit_tls = info->jit_data;
1042 info->jit_data = NULL;
1044 mono_set_jit_tls (NULL);
1046 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1047 if (mono_get_lmf ()) {
1048 mono_set_lmf (NULL);
1049 mono_set_lmf_addr (NULL);
1051 } else {
1052 info = mono_thread_info_lookup (tid);
1053 if (info) {
1054 jit_tls = info->jit_data;
1055 info->jit_data = NULL;
1057 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1060 if (jit_tls)
1061 free_jit_tls_data (jit_tls);
1064 MonoJumpInfo *
1065 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1067 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1069 ji->ip.i = ip;
1070 ji->type = type;
1071 ji->data.target = target;
1072 ji->next = list;
1074 return ji;
1077 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1079 static const char* const patch_info_str[] = {
1080 #define PATCH_INFO(a,b) "" #a,
1081 #include "patch-info.h"
1082 #undef PATCH_INFO
1085 const char*
1086 mono_ji_type_to_string (MonoJumpInfoType type)
1088 return patch_info_str [type];
1091 void
1092 mono_print_ji (const MonoJumpInfo *ji)
1094 switch (ji->type) {
1095 case MONO_PATCH_INFO_RGCTX_FETCH: {
1096 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1098 printf ("[RGCTX_FETCH ");
1099 mono_print_ji (entry->data);
1100 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1101 break;
1103 case MONO_PATCH_INFO_METHODCONST: {
1104 char *s = mono_method_full_name (ji->data.method, TRUE);
1105 printf ("[METHODCONST - %s]", s);
1106 g_free (s);
1107 break;
1109 case MONO_PATCH_INFO_JIT_ICALL: {
1110 printf ("[JIT_ICALL - %s]", ji->data.name);
1111 break;
1113 case MONO_PATCH_INFO_CLASS: {
1114 char *name = mono_class_full_name (ji->data.klass);
1115 printf ("[CLASS - %s]", name);
1116 g_free (name);
1117 break;
1119 default:
1120 printf ("[%s]", patch_info_str [ji->type]);
1121 break;
1125 #else
1127 const char*
1128 mono_ji_type_to_string (MonoJumpInfoType type)
1130 return "";
1133 void
1134 mono_print_ji (const MonoJumpInfo *ji)
1138 #endif
1141 * mono_patch_info_dup_mp:
1143 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1145 MonoJumpInfo*
1146 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1148 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1149 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1151 switch (patch_info->type) {
1152 case MONO_PATCH_INFO_RVA:
1153 case MONO_PATCH_INFO_LDSTR:
1154 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1155 case MONO_PATCH_INFO_LDTOKEN:
1156 case MONO_PATCH_INFO_DECLSEC:
1157 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1158 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1159 break;
1160 case MONO_PATCH_INFO_SWITCH:
1161 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1162 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1163 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1164 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1165 break;
1166 case MONO_PATCH_INFO_RGCTX_FETCH:
1167 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1168 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1169 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1170 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1171 break;
1172 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1173 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1174 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1175 break;
1176 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1177 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1178 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1179 break;
1180 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1181 MonoGSharedVtMethodInfo *info;
1182 MonoGSharedVtMethodInfo *oinfo;
1183 int i;
1185 oinfo = patch_info->data.gsharedvt_method;
1186 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1187 res->data.gsharedvt_method = info;
1188 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1189 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1190 for (i = 0; i < oinfo->num_entries; ++i) {
1191 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1192 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1194 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1196 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1197 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1198 break;
1200 case MONO_PATCH_INFO_VIRT_METHOD: {
1201 MonoJumpInfoVirtMethod *info;
1202 MonoJumpInfoVirtMethod *oinfo;
1204 oinfo = patch_info->data.virt_method;
1205 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1206 res->data.virt_method = info;
1207 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1208 break;
1210 default:
1211 break;
1214 return res;
1217 guint
1218 mono_patch_info_hash (gconstpointer data)
1220 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1222 switch (ji->type) {
1223 case MONO_PATCH_INFO_RVA:
1224 case MONO_PATCH_INFO_LDSTR:
1225 case MONO_PATCH_INFO_LDTOKEN:
1226 case MONO_PATCH_INFO_DECLSEC:
1227 return (ji->type << 8) | ji->data.token->token;
1228 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1229 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1230 case MONO_PATCH_INFO_JIT_ICALL:
1231 return (ji->type << 8) | g_str_hash (ji->data.name);
1232 case MONO_PATCH_INFO_VTABLE:
1233 case MONO_PATCH_INFO_CLASS:
1234 case MONO_PATCH_INFO_IID:
1235 case MONO_PATCH_INFO_ADJUSTED_IID:
1236 case MONO_PATCH_INFO_METHODCONST:
1237 case MONO_PATCH_INFO_METHOD:
1238 case MONO_PATCH_INFO_METHOD_JUMP:
1239 case MONO_PATCH_INFO_IMAGE:
1240 case MONO_PATCH_INFO_ICALL_ADDR:
1241 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1242 case MONO_PATCH_INFO_FIELD:
1243 case MONO_PATCH_INFO_SFLDA:
1244 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1245 case MONO_PATCH_INFO_METHOD_RGCTX:
1246 case MONO_PATCH_INFO_SIGNATURE:
1247 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1248 case MONO_PATCH_INFO_AOT_JIT_INFO:
1249 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1250 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1251 return (ji->type << 8) | (gssize)ji->data.target;
1252 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1253 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1254 case MONO_PATCH_INFO_RGCTX_FETCH:
1255 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1256 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1258 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1260 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1261 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1262 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1263 case MONO_PATCH_INFO_GC_NURSERY_START:
1264 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1265 case MONO_PATCH_INFO_GOT_OFFSET:
1266 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1267 case MONO_PATCH_INFO_AOT_MODULE:
1268 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1269 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1270 return (ji->type << 8);
1271 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1272 return (ji->type << 8) | (ji->data.index);
1273 case MONO_PATCH_INFO_SWITCH:
1274 return (ji->type << 8) | ji->data.table->table_size;
1275 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1276 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1277 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1278 /* Hash on the selector name */
1279 return g_str_hash (ji->data.target);
1280 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1281 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1282 case MONO_PATCH_INFO_LDSTR_LIT:
1283 return g_str_hash (ji->data.target);
1284 case MONO_PATCH_INFO_VIRT_METHOD: {
1285 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1287 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1289 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1290 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1291 return (ji->type << 8) | g_str_hash (ji->data.target);
1292 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1293 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1294 default:
1295 printf ("info type: %d\n", ji->type);
1296 mono_print_ji (ji); printf ("\n");
1297 g_assert_not_reached ();
1298 return 0;
1303 * mono_patch_info_equal:
1305 * This might fail to recognize equivalent patches, i.e. floats, so its only
1306 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1307 * in AOT.
1309 gint
1310 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1312 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1313 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1315 if (ji1->type != ji2->type)
1316 return 0;
1318 switch (ji1->type) {
1319 case MONO_PATCH_INFO_RVA:
1320 case MONO_PATCH_INFO_LDSTR:
1321 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1322 case MONO_PATCH_INFO_LDTOKEN:
1323 case MONO_PATCH_INFO_DECLSEC:
1324 if ((ji1->data.token->image != ji2->data.token->image) ||
1325 (ji1->data.token->token != ji2->data.token->token) ||
1326 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1327 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1328 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1329 return 0;
1330 break;
1331 case MONO_PATCH_INFO_JIT_ICALL:
1332 return g_str_equal (ji1->data.name, ji2->data.name);
1333 case MONO_PATCH_INFO_RGCTX_FETCH:
1334 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1335 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1336 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1338 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);
1340 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1341 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1342 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1344 return c1->sig == c2->sig && c1->method == c2->method;
1346 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1347 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1348 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1349 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;
1350 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1351 return ji1->data.index == ji2->data.index;
1352 case MONO_PATCH_INFO_VIRT_METHOD:
1353 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1354 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1355 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1356 if (ji1->data.target == ji2->data.target)
1357 return 1;
1358 return strcmp ((const char*)ji1->data.target, (const char*)ji2->data.target) == 0 ? 1 : 0;
1359 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1360 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1361 default:
1362 if (ji1->data.target != ji2->data.target)
1363 return 0;
1364 break;
1367 return 1;
1370 gpointer
1371 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1373 unsigned char *ip = patch_info->ip.i + code;
1374 gconstpointer target = NULL;
1376 error_init (error);
1378 switch (patch_info->type) {
1379 case MONO_PATCH_INFO_BB:
1381 * FIXME: This could be hit for methods without a prolog. Should use -1
1382 * but too much code depends on a 0 initial value.
1384 //g_assert (patch_info->data.bb->native_offset);
1385 target = patch_info->data.bb->native_offset + code;
1386 break;
1387 case MONO_PATCH_INFO_ABS:
1388 target = patch_info->data.target;
1389 break;
1390 case MONO_PATCH_INFO_LABEL:
1391 target = patch_info->data.inst->inst_c0 + code;
1392 break;
1393 case MONO_PATCH_INFO_IP:
1394 target = ip;
1395 break;
1396 case MONO_PATCH_INFO_METHOD_REL:
1397 target = code + patch_info->data.offset;
1398 break;
1399 case MONO_PATCH_INFO_JIT_ICALL: {
1400 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1401 if (!mi) {
1402 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL %s", patch_info->data.name);
1403 g_assert_not_reached ();
1405 target = mono_icall_get_wrapper (mi);
1406 break;
1408 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1409 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1410 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1411 if (!mi) {
1412 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1413 g_assert_not_reached ();
1415 target = mi->func;
1416 break;
1418 case MONO_PATCH_INFO_METHOD_JUMP:
1419 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1420 if (!mono_error_ok (error))
1421 return NULL;
1422 break;
1423 case MONO_PATCH_INFO_METHOD:
1424 if (patch_info->data.method == method) {
1425 target = code;
1426 } else {
1427 /* get the trampoline to the method from the domain */
1428 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1429 if (!mono_error_ok (error))
1430 return NULL;
1432 break;
1433 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1434 gpointer code_slot;
1436 mono_domain_lock (domain);
1437 if (!domain_jit_info (domain)->method_code_hash)
1438 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1439 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1440 if (!code_slot) {
1441 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1442 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1444 mono_domain_unlock (domain);
1445 target = code_slot;
1446 break;
1448 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1449 target = (gpointer)&mono_polling_required;
1450 break;
1451 case MONO_PATCH_INFO_SWITCH: {
1452 gpointer *jump_table;
1453 int i;
1454 if (method && method->dynamic) {
1455 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1456 } else {
1457 if (mono_aot_only) {
1458 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1459 } else {
1460 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1464 for (i = 0; i < patch_info->data.table->table_size; i++) {
1465 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1468 target = jump_table;
1469 break;
1471 case MONO_PATCH_INFO_METHODCONST:
1472 case MONO_PATCH_INFO_CLASS:
1473 case MONO_PATCH_INFO_IMAGE:
1474 case MONO_PATCH_INFO_FIELD:
1475 case MONO_PATCH_INFO_SIGNATURE:
1476 case MONO_PATCH_INFO_AOT_MODULE:
1477 target = patch_info->data.target;
1478 break;
1479 case MONO_PATCH_INFO_IID:
1480 mono_class_init (patch_info->data.klass);
1481 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1482 break;
1483 case MONO_PATCH_INFO_ADJUSTED_IID:
1484 mono_class_init (patch_info->data.klass);
1485 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1486 break;
1487 case MONO_PATCH_INFO_VTABLE:
1488 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1489 mono_error_assert_ok (error);
1490 break;
1491 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1492 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1494 if (del_tramp->is_virtual)
1495 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1496 else
1497 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1498 break;
1500 case MONO_PATCH_INFO_SFLDA: {
1501 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1502 mono_error_assert_ok (error);
1504 if (mono_class_field_is_special_static (patch_info->data.field)) {
1505 gpointer addr = NULL;
1507 mono_domain_lock (domain);
1508 if (domain->special_static_fields)
1509 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1510 mono_domain_unlock (domain);
1511 g_assert (addr);
1512 return addr;
1515 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1516 /* Done by the generated code */
1518 else {
1519 if (run_cctors) {
1520 if (!mono_runtime_class_init_full (vtable, error)) {
1521 return NULL;
1525 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1526 break;
1528 case MONO_PATCH_INFO_RVA: {
1529 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1530 guint32 rva;
1532 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1533 target = mono_image_rva_map (patch_info->data.token->image, rva);
1534 break;
1536 case MONO_PATCH_INFO_R4:
1537 case MONO_PATCH_INFO_R8:
1538 target = patch_info->data.target;
1539 break;
1540 case MONO_PATCH_INFO_EXC_NAME:
1541 target = patch_info->data.name;
1542 break;
1543 case MONO_PATCH_INFO_LDSTR:
1544 target =
1545 mono_ldstr_checked (domain, patch_info->data.token->image,
1546 mono_metadata_token_index (patch_info->data.token->token), error);
1547 break;
1548 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1549 gpointer handle;
1550 MonoClass *handle_class;
1552 handle = mono_ldtoken_checked (patch_info->data.token->image,
1553 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1554 if (!mono_error_ok (error))
1555 return NULL;
1556 mono_class_init (handle_class);
1557 mono_class_init (mono_class_from_mono_type_internal ((MonoType *)handle));
1559 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1560 if (!mono_error_ok (error))
1561 return NULL;
1562 break;
1564 case MONO_PATCH_INFO_LDTOKEN: {
1565 gpointer handle;
1566 MonoClass *handle_class;
1568 handle = mono_ldtoken_checked (patch_info->data.token->image,
1569 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1570 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1571 mono_class_init (handle_class);
1573 target = handle;
1574 break;
1576 case MONO_PATCH_INFO_DECLSEC:
1577 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1578 break;
1579 case MONO_PATCH_INFO_ICALL_ADDR:
1580 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1581 /* run_cctors == 0 -> AOT */
1582 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1583 const char *exc_class;
1584 const char *exc_arg;
1586 if (run_cctors) {
1587 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1588 if (!target) {
1589 if (mono_aot_only) {
1590 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1591 return NULL;
1593 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));
1595 } else {
1596 target = NULL;
1598 } else {
1599 target = mono_lookup_internal_call (patch_info->data.method);
1601 if (!target && run_cctors)
1602 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1604 break;
1605 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1606 target = mono_thread_interruption_request_flag ();
1607 break;
1608 case MONO_PATCH_INFO_METHOD_RGCTX:
1609 target = mini_method_get_rgctx (patch_info->data.method);
1610 break;
1611 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1612 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1614 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1615 break;
1617 case MONO_PATCH_INFO_BB_OVF:
1618 case MONO_PATCH_INFO_EXC_OVF:
1619 case MONO_PATCH_INFO_GOT_OFFSET:
1620 case MONO_PATCH_INFO_NONE:
1621 break;
1622 case MONO_PATCH_INFO_RGCTX_FETCH: {
1623 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1625 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1626 break;
1628 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1629 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1630 if (!run_cctors)
1631 /* AOT, not needed */
1632 target = NULL;
1633 else
1634 target = mono_arch_get_seq_point_info (domain, code);
1635 break;
1636 #endif
1637 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1638 int card_table_shift_bits;
1639 gpointer card_table_mask;
1641 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1642 break;
1644 case MONO_PATCH_INFO_GC_NURSERY_START: {
1645 int shift_bits;
1646 size_t size;
1648 target = mono_gc_get_nursery (&shift_bits, &size);
1649 break;
1651 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1652 int shift_bits;
1653 size_t size;
1655 mono_gc_get_nursery (&shift_bits, &size);
1657 target = (gpointer)(gssize)shift_bits;
1658 break;
1660 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1661 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1662 break;
1664 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1665 target = NULL;
1666 break;
1668 case MONO_PATCH_INFO_LDSTR_LIT: {
1669 int len;
1670 char *s;
1672 len = strlen ((const char *)patch_info->data.target);
1673 s = (char *)mono_domain_alloc0 (domain, len + 1);
1674 memcpy (s, patch_info->data.target, len);
1675 target = s;
1677 break;
1679 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1680 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1681 break;
1682 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1683 target = mono_tls_get_tls_getter ((MonoTlsKey)patch_info->data.index, FALSE);
1684 break;
1685 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1686 target = mono_tls_get_tls_setter ((MonoTlsKey)patch_info->data.index, FALSE);
1687 break;
1688 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1689 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1690 break;
1692 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1693 target = (gpointer) &mono_profiler_state.exception_clause_count;
1694 break;
1696 default:
1697 g_assert_not_reached ();
1700 return (gpointer)target;
1704 * mini_register_jump_site:
1706 * Register IP as a jump/tailcall site which calls METHOD.
1707 * This is needed because common_call_trampoline () cannot patch
1708 * the call site because the caller ip is not available for jumps.
1710 void
1711 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1713 MonoJumpList *jlist;
1715 MonoMethod *shared_method = mini_method_to_shared (method);
1716 method = shared_method ? shared_method : method;
1718 mono_domain_lock (domain);
1719 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1720 if (!jlist) {
1721 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1722 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1724 jlist->list = g_slist_prepend (jlist->list, ip);
1725 mono_domain_unlock (domain);
1729 * mini_patch_jump_sites:
1731 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1733 void
1734 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1736 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1738 if (!hash)
1739 return;
1741 MonoJumpInfo patch_info;
1742 MonoJumpList *jlist;
1743 GSList *tmp;
1745 /* The caller/callee might use different instantiations */
1746 MonoMethod *shared_method = mini_method_to_shared (method);
1747 method = shared_method ? shared_method : method;
1749 mono_domain_lock (domain);
1750 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1751 if (jlist)
1752 g_hash_table_remove (hash, method);
1753 mono_domain_unlock (domain);
1754 if (jlist) {
1755 patch_info.next = NULL;
1756 patch_info.ip.i = 0;
1757 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1758 patch_info.data.method = method;
1760 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1761 for (tmp = jlist->list; tmp; tmp = tmp->next)
1762 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1763 #else
1764 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1765 // for gshared methods
1766 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1767 ERROR_DECL (error);
1768 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1769 mono_error_assert_ok (error);
1771 #endif
1775 void
1776 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1778 MonoGenericInst *inst;
1779 int i;
1781 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1783 if (context && context->class_inst) {
1784 inst = context->class_inst;
1785 for (i = 0; i < inst->type_argc; ++i) {
1786 MonoType *type = inst->type_argv [i];
1788 if (mini_is_gsharedvt_gparam (type))
1789 gsctx->is_gsharedvt = TRUE;
1792 if (context && context->method_inst) {
1793 inst = context->method_inst;
1795 for (i = 0; i < inst->type_argc; ++i) {
1796 MonoType *type = inst->type_argv [i];
1798 if (mini_is_gsharedvt_gparam (type))
1799 gsctx->is_gsharedvt = TRUE;
1805 * LOCKING: Acquires the jit code hash lock.
1807 MonoJitInfo*
1808 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1810 MonoJitInfo *ji;
1811 static gboolean inited = FALSE;
1812 static int lookups = 0;
1813 static int failed_lookups = 0;
1815 mono_domain_jit_code_hash_lock (domain);
1816 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1817 if (!ji && shared) {
1818 /* Try generic sharing */
1819 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1820 if (ji && !ji->has_generic_jit_info)
1821 ji = NULL;
1822 if (!inited) {
1823 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1824 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1825 inited = TRUE;
1828 ++lookups;
1829 if (!ji)
1830 ++failed_lookups;
1832 mono_domain_jit_code_hash_unlock (domain);
1834 return ji;
1837 static MonoJitInfo*
1838 lookup_method (MonoDomain *domain, MonoMethod *method)
1840 ERROR_DECL (error);
1841 MonoJitInfo *ji;
1842 MonoMethod *shared;
1844 ji = mini_lookup_method (domain, method, NULL);
1846 if (!ji) {
1847 if (!mono_method_is_generic_sharable (method, FALSE))
1848 return NULL;
1849 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1850 mono_error_assert_ok (error);
1851 ji = mini_lookup_method (domain, method, shared);
1854 return ji;
1857 MonoClass*
1858 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1860 ERROR_DECL (error);
1861 MonoClass *klass;
1863 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1864 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1865 if (context) {
1866 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1867 mono_error_cleanup (error); /* FIXME don't swallow the error */
1869 } else {
1870 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1871 mono_error_cleanup (error); /* FIXME don't swallow the error */
1873 if (klass)
1874 mono_class_init (klass);
1875 return klass;
1878 #if ENABLE_JIT_MAP
1879 static FILE* perf_map_file;
1881 void
1882 mono_enable_jit_map (void)
1884 if (!perf_map_file) {
1885 char name [64];
1886 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1887 unlink (name);
1888 perf_map_file = fopen (name, "w");
1892 void
1893 mono_emit_jit_tramp (void *start, int size, const char *desc)
1895 if (perf_map_file)
1896 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1899 void
1900 mono_emit_jit_map (MonoJitInfo *jinfo)
1902 if (perf_map_file) {
1903 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1904 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1905 g_free (name);
1909 gboolean
1910 mono_jit_map_is_enabled (void)
1912 return perf_map_file != NULL;
1915 #endif
1917 static void
1918 no_gsharedvt_in_wrapper (void)
1920 g_assert_not_reached ();
1924 Overall algorithm:
1926 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.
1927 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1928 Dependency management in this case is too complex to justify implementing it.
1930 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1932 TODO:
1933 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1934 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1935 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1936 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1938 typedef struct {
1939 MonoMethod *method;
1940 MonoDomain *domain;
1941 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1942 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1943 int threads_waiting; /* Number of threads waiting on this job */
1944 gboolean has_cond; /* True if @cond was initialized */
1945 gboolean done; /* True if the method finished JIT'ing */
1946 MonoCoopCond cond; /* Cond sleeping threads wait one */
1947 } JitCompilationEntry;
1949 typedef struct {
1950 GPtrArray *in_flight_methods; //JitCompilationEntry*
1951 MonoCoopMutex lock;
1952 } JitCompilationData;
1955 Timeout, in millisecounds, that we wait other threads to finish JITing.
1956 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.
1958 #define MAX_JIT_TIMEOUT_MS 1000
1961 static JitCompilationData compilation_data;
1962 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
1964 static void
1965 mini_jit_init_job_control (void)
1967 mono_coop_mutex_init (&compilation_data.lock);
1968 compilation_data.in_flight_methods = g_ptr_array_new ();
1971 static void
1972 lock_compilation_data (void)
1974 mono_coop_mutex_lock (&compilation_data.lock);
1977 static void
1978 unlock_compilation_data (void)
1980 mono_coop_mutex_unlock (&compilation_data.lock);
1983 static JitCompilationEntry*
1984 find_method (MonoMethod *method, MonoDomain *domain)
1986 int i;
1987 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1988 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
1989 if (e->method == method && e->domain == domain)
1990 return e;
1993 return NULL;
1996 static void
1997 add_current_thread (MonoJitTlsData *jit_tls)
1999 ++jit_tls->active_jit_methods;
2002 static void
2003 unref_jit_entry (JitCompilationEntry *entry)
2005 --entry->ref_count;
2006 if (entry->ref_count)
2007 return;
2008 if (entry->has_cond)
2009 mono_coop_cond_destroy (&entry->cond);
2010 g_free (entry);
2014 * Returns true if this method waited successfully for another thread to JIT it
2016 static gboolean
2017 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2019 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2020 JitCompilationEntry *entry;
2022 static gboolean inited;
2023 if (!inited) {
2024 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2025 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2026 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2027 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2028 inited = TRUE;
2031 lock_compilation_data ();
2033 if (!(entry = find_method (method, domain))) {
2034 entry = g_new0 (JitCompilationEntry, 1);
2035 entry->method = method;
2036 entry->domain = domain;
2037 entry->compilation_count = entry->ref_count = 1;
2038 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2039 g_assert (find_method (method, domain) == entry);
2040 add_current_thread (jit_tls);
2042 unlock_compilation_data ();
2043 return FALSE;
2044 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2045 //We can't suspend the current thread if it's already JITing a method.
2046 //Dependency management is too compilated and we want to get rid of this anyways.
2048 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2049 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2051 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2052 ++entry->compilation_count;
2053 ++jit_methods_multiple;
2054 ++jit_tls->active_jit_methods;
2056 unlock_compilation_data ();
2057 return FALSE;
2058 } else {
2059 ++jit_methods_waited;
2060 ++entry->ref_count;
2062 if (!entry->has_cond) {
2063 mono_coop_cond_init (&entry->cond);
2064 entry->has_cond = TRUE;
2067 while (TRUE) {
2068 ++entry->threads_waiting;
2070 g_assert (entry->has_cond);
2071 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2072 --entry->threads_waiting;
2074 if (entry->done) {
2075 unref_jit_entry (entry);
2076 unlock_compilation_data ();
2077 return TRUE;
2078 } else {
2079 //We hit the timeout or a spurious wakeup, fallback to JITing
2080 g_assert (entry->ref_count > 1);
2081 unref_jit_entry (entry);
2082 ++jit_spurious_wakeups_or_timeouts;
2084 ++entry->compilation_count;
2085 ++jit_methods_multiple;
2086 ++jit_tls->active_jit_methods;
2088 unlock_compilation_data ();
2089 return FALSE;
2095 static void
2096 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2098 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2100 lock_compilation_data ();
2102 g_assert (jit_tls->active_jit_methods > 0);
2103 --jit_tls->active_jit_methods;
2105 JitCompilationEntry *entry = find_method (method, target_domain);
2106 g_assert (entry); // It would be weird to fail
2107 entry->done = TRUE;
2109 if (entry->threads_waiting) {
2110 g_assert (entry->has_cond);
2111 mono_coop_cond_broadcast (&entry->cond);
2114 if (--entry->compilation_count == 0) {
2115 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2116 unref_jit_entry (entry);
2119 unlock_compilation_data ();
2122 static MonoJitInfo*
2123 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2125 MonoDomain *domain = mono_get_root_domain ();
2126 MonoJitInfo *jinfo;
2127 guint8 *uw_info;
2128 guint32 info_len;
2130 if (info->uw_info) {
2131 uw_info = info->uw_info;
2132 info_len = info->uw_info_len;
2133 } else {
2134 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2137 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2138 jinfo->d.method = wrapper;
2139 jinfo->code_start = info->code;
2140 jinfo->code_size = info->code_size;
2141 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2143 if (!info->uw_info)
2144 g_free (uw_info);
2146 return jinfo;
2149 static gpointer
2150 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2152 MonoJitInfo *jinfo;
2153 gpointer code;
2155 if (mono_llvm_only) {
2156 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2157 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2159 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2161 * These wrappers are only created for signatures which are in the program, but
2162 * sometimes we load methods too eagerly and have to create them even if they
2163 * will never be called.
2165 return (gpointer)no_gsharedvt_in_wrapper;
2170 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2171 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2172 MonoMethod *nm;
2173 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2175 if (!piinfo->addr) {
2176 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2177 piinfo->addr = mono_lookup_internal_call (method);
2178 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2179 #ifdef HOST_WIN32
2180 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);
2181 #else
2182 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);
2183 #endif
2184 else
2185 mono_lookup_pinvoke_call (method, NULL, NULL);
2187 nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2188 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2189 return_val_if_nok (error, NULL);
2190 code = mono_get_addr_from_ftnptr (compiled_method);
2191 jinfo = mono_jit_info_table_find (target_domain, code);
2192 if (!jinfo)
2193 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2194 if (jinfo)
2195 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2196 return code;
2197 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2198 const char *name = method->name;
2199 char *full_name;
2200 MonoMethod *nm;
2202 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2203 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2204 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2205 g_assert (mi);
2207 * We need to make sure this wrapper
2208 * is compiled because it might end up
2209 * in an (M)RGCTX if generic sharing
2210 * is enabled, and would be called
2211 * indirectly. If it were a
2212 * trampoline we'd try to patch that
2213 * indirect call, which is not
2214 * possible.
2216 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2217 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2218 if (mono_llvm_only) {
2219 nm = mono_marshal_get_delegate_invoke (method, NULL);
2220 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2221 return_val_if_nok (error, NULL);
2222 return mono_get_addr_from_ftnptr (compiled_ptr);
2225 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2226 if (mono_use_interpreter)
2227 return NULL;
2229 return mono_create_delegate_trampoline (target_domain, method->klass);
2230 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2231 nm = mono_marshal_get_delegate_begin_invoke (method);
2232 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2233 return_val_if_nok (error, NULL);
2234 return mono_get_addr_from_ftnptr (compiled_ptr);
2235 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2236 nm = mono_marshal_get_delegate_end_invoke (method);
2237 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2238 return_val_if_nok (error, NULL);
2239 return mono_get_addr_from_ftnptr (compiled_ptr);
2243 full_name = mono_method_full_name (method, TRUE);
2244 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2245 g_free (full_name);
2246 return NULL;
2249 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2250 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2252 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2253 static MonoTrampInfo *in_tinfo, *out_tinfo;
2254 MonoTrampInfo *tinfo;
2255 MonoJitInfo *jinfo;
2256 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2258 if (is_in && in_tinfo)
2259 return in_tinfo->code;
2260 else if (!is_in && out_tinfo)
2261 return out_tinfo->code;
2264 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2265 * works.
2266 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2268 if (mono_ee_features.use_aot_trampolines)
2269 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2270 else
2271 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2272 jinfo = create_jit_info_for_trampoline (method, tinfo);
2273 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2274 if (is_in)
2275 in_tinfo = tinfo;
2276 else
2277 out_tinfo = tinfo;
2278 return tinfo->code;
2282 return NULL;
2285 static gpointer
2286 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2288 MonoDomain *target_domain, *domain = mono_domain_get ();
2289 MonoJitInfo *info;
2290 gpointer code = NULL, p;
2291 MonoJitInfo *ji;
2292 MonoJitICallInfo *callinfo = NULL;
2293 WrapperInfo *winfo = NULL;
2294 gboolean use_interp = FALSE;
2296 error_init (error);
2298 if (mono_ee_features.force_use_interpreter && !jit_only)
2299 use_interp = TRUE;
2300 if (!use_interp && mono_interp_only_classes) {
2301 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2302 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2303 use_interp = TRUE;
2306 if (use_interp) {
2307 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2308 if (code)
2309 return code;
2312 if (mono_llvm_only)
2313 /* Should be handled by the caller */
2314 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2317 * ICALL wrappers are handled specially, since there is only one copy of them
2318 * shared by all appdomains.
2320 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2321 winfo = mono_marshal_get_wrapper_info (method);
2322 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2323 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2324 g_assert (callinfo);
2326 /* Must be domain neutral since there is only one copy */
2327 opt |= MONO_OPT_SHARED;
2328 } else {
2329 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2330 opt &= ~MONO_OPT_SHARED;
2333 if (opt & MONO_OPT_SHARED)
2334 target_domain = mono_get_root_domain ();
2335 else
2336 target_domain = domain;
2338 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2339 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2341 g_assert (info);
2342 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2343 MonoGenericContext *ctx = NULL;
2344 if (method->is_inflated)
2345 ctx = mono_method_get_context (method);
2346 method = info->d.synchronized_inner.method;
2347 if (ctx) {
2348 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2349 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2354 lookup_start:
2355 info = lookup_method (target_domain, method);
2356 if (info) {
2357 /* We can't use a domain specific method in another domain */
2358 if (! ((domain != target_domain) && !info->domain_neutral)) {
2359 MonoVTable *vtable;
2361 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2362 vtable = mono_class_vtable_checked (domain, method->klass, error);
2363 if (!is_ok (error))
2364 return NULL;
2365 g_assert (vtable);
2366 if (!mono_runtime_class_init_full (vtable, error))
2367 return NULL;
2368 return mono_create_ftnptr (target_domain, info->code_start);
2372 #ifdef MONO_USE_AOT_COMPILER
2373 if (opt & MONO_OPT_AOT) {
2374 MonoDomain *domain = NULL;
2376 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2377 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2378 g_assert (info);
2379 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2380 /* AOT'd wrappers for interp must be owned by root domain */
2381 domain = mono_get_root_domain ();
2384 if (!domain)
2385 domain = mono_domain_get ();
2387 mono_class_init (method->klass);
2389 if ((code = mono_aot_get_method (domain, method, error))) {
2390 MonoVTable *vtable;
2392 if (mono_gc_is_critical_method (method)) {
2394 * The suspend code needs to be able to lookup these methods by ip in async context,
2395 * so preload their jit info.
2397 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2398 g_assert (ji);
2402 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2403 * This is not a problem, since it will be initialized when the method is first
2404 * called by init_method ().
2406 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2407 vtable = mono_class_vtable_checked (domain, method->klass, error);
2408 mono_error_assert_ok (error);
2409 if (!mono_runtime_class_init_full (vtable, error))
2410 return NULL;
2413 if (!is_ok (error))
2414 return NULL;
2416 #endif
2418 if (!code)
2419 code = compile_special (method, target_domain, error);
2421 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER)
2422 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2424 if (!code) {
2425 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2426 char *full_name = mono_type_get_full_name (method->klass);
2427 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2428 g_free (full_name);
2429 return NULL;
2432 if (mono_aot_only) {
2433 char *fullname = mono_method_get_full_name (method);
2434 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);
2435 g_free (fullname);
2437 return NULL;
2440 if (wait_or_register_method_to_compile (method, target_domain))
2441 goto lookup_start;
2442 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2443 unregister_method_for_compile (method, target_domain);
2445 if (!mono_error_ok (error))
2446 return NULL;
2448 if (!code && mono_llvm_only) {
2449 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2450 g_assert_not_reached ();
2453 if (!code)
2454 return NULL;
2456 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2457 #ifndef HOST_WASM
2458 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2459 MonoDomain *d;
2462 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2464 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2465 g_assert (ji);
2467 #endif
2469 p = mono_create_ftnptr (target_domain, code);
2471 if (callinfo) {
2472 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2473 mono_loader_lock ();
2474 mono_jit_lock ();
2475 if (!callinfo->wrapper) {
2476 callinfo->wrapper = p;
2477 mono_register_jit_icall_wrapper (callinfo, p);
2479 mono_jit_unlock ();
2480 mono_loader_unlock ();
2483 return p;
2486 gpointer
2487 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2489 gpointer code;
2491 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2492 return code;
2496 * mono_jit_compile_method_jit_only:
2498 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2500 gpointer
2501 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2503 gpointer code;
2505 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2506 return code;
2509 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2510 static void
2511 invalidated_delegate_trampoline (char *desc)
2513 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2514 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2515 desc);
2517 #endif
2520 * mono_jit_free_method:
2522 * Free all memory allocated by the JIT for METHOD.
2524 static void
2525 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2527 MonoJitDynamicMethodInfo *ji;
2528 gboolean destroy = TRUE, removed;
2529 GHashTableIter iter;
2530 MonoJumpList *jlist;
2531 MonoJitDomainInfo *info = domain_jit_info (domain);
2533 g_assert (method->dynamic);
2535 if (mono_use_interpreter) {
2536 mono_domain_jit_code_hash_lock (domain);
2537 /* InterpMethod is allocated in the domain mempool. We might haven't
2538 * allocated an InterpMethod for this instance yet */
2539 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2540 mono_domain_jit_code_hash_unlock (domain);
2543 mono_domain_lock (domain);
2544 ji = mono_dynamic_code_hash_lookup (domain, method);
2545 mono_domain_unlock (domain);
2547 if (!ji)
2548 return;
2550 mono_debug_remove_method (method, domain);
2551 mono_lldb_remove_method (domain, method, ji);
2553 mono_domain_lock (domain);
2554 g_hash_table_remove (info->dynamic_code_hash, method);
2555 mono_domain_jit_code_hash_lock (domain);
2556 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2557 g_assert (removed);
2558 mono_domain_jit_code_hash_unlock (domain);
2559 g_hash_table_remove (info->jump_trampoline_hash, method);
2560 g_hash_table_remove (info->seq_points, method);
2562 ji->ji->seq_points = NULL;
2564 /* requires the domain lock - took above */
2565 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2567 /* Remove jump targets in this method */
2568 g_hash_table_iter_init (&iter, info->jump_target_hash);
2569 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2570 GSList *tmp, *remove;
2572 remove = NULL;
2573 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2574 guint8 *ip = (guint8 *)tmp->data;
2576 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2577 remove = g_slist_prepend (remove, tmp);
2579 for (tmp = remove; tmp; tmp = tmp->next) {
2580 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2582 g_slist_free (remove);
2584 mono_domain_unlock (domain);
2586 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2587 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2589 * Instead of freeing the code, change it to call an error routine
2590 * so people can fix their code.
2592 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2593 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2595 g_free (type);
2596 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2597 destroy = FALSE;
2599 #endif
2602 * This needs to be done before freeing code_mp, since the code address is the
2603 * key in the table, so if we free the code_mp first, another thread can grab the
2604 * same code address and replace our entry in the table.
2606 mono_jit_info_table_remove (domain, ji->ji);
2608 if (destroy)
2609 mono_code_manager_destroy (ji->code_mp);
2610 g_free (ji);
2613 gpointer
2614 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2616 gpointer code;
2617 MonoJitInfo *ji;
2619 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2620 if (!code) {
2621 ERROR_DECL_VALUE (oerror);
2623 /* Might be AOTed code */
2624 mono_class_init (method->klass);
2625 code = mono_aot_get_method (domain, method, &oerror);
2626 if (code) {
2627 mono_error_assert_ok (&oerror);
2628 ji = mono_jit_info_table_find (domain, code);
2629 } else {
2630 if (!is_ok (&oerror))
2631 mono_error_cleanup (&oerror);
2633 /* Might be interpreted */
2634 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2638 *out_ji = ji;
2640 return code;
2643 gpointer
2644 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2646 MonoDomain *target_domain;
2647 MonoJitInfo *info;
2649 if (default_opt & MONO_OPT_SHARED)
2650 target_domain = mono_get_root_domain ();
2651 else
2652 target_domain = domain;
2654 info = lookup_method (target_domain, method);
2655 if (info) {
2656 /* We can't use a domain specific method in another domain */
2657 if (! ((domain != target_domain) && !info->domain_neutral)) {
2658 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2659 if (ji)
2660 *ji = info;
2661 return info->code_start;
2665 if (ji)
2666 *ji = NULL;
2667 return NULL;
2670 static guint32 bisect_opt = 0;
2671 static GHashTable *bisect_methods_hash = NULL;
2673 void
2674 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2676 FILE *file;
2677 char method_name [2048];
2679 bisect_opt = opt;
2680 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2681 g_assert (bisect_methods_hash);
2683 file = fopen (method_list_filename, "r");
2684 g_assert (file);
2686 while (fgets (method_name, sizeof (method_name), file)) {
2687 size_t len = strlen (method_name);
2688 g_assert (len > 0);
2689 g_assert (method_name [len - 1] == '\n');
2690 method_name [len - 1] = 0;
2691 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2693 g_assert (feof (file));
2696 gboolean mono_do_single_method_regression = FALSE;
2697 guint32 mono_single_method_regression_opt = 0;
2698 MonoMethod *mono_current_single_method;
2699 GSList *mono_single_method_list;
2700 GHashTable *mono_single_method_hash;
2702 guint32
2703 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2705 g_assert (method);
2707 if (bisect_methods_hash) {
2708 char *name = mono_method_full_name (method, TRUE);
2709 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2710 g_free (name);
2711 if (res)
2712 return default_opt | bisect_opt;
2714 if (!mono_do_single_method_regression)
2715 return default_opt;
2716 if (!mono_current_single_method) {
2717 if (!mono_single_method_hash)
2718 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2719 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2720 g_hash_table_insert (mono_single_method_hash, method, method);
2721 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2723 return default_opt;
2725 if (method == mono_current_single_method)
2726 return mono_single_method_regression_opt;
2727 return default_opt;
2730 gpointer
2731 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2733 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2736 typedef struct {
2737 MonoMethod *method;
2738 gpointer compiled_method;
2739 gpointer runtime_invoke;
2740 MonoVTable *vtable;
2741 MonoDynCallInfo *dyn_call_info;
2742 MonoClass *ret_box_class;
2743 MonoMethodSignature *sig;
2744 gboolean gsharedvt_invoke;
2745 gboolean use_interp;
2746 gpointer *wrapper_arg;
2747 } RuntimeInvokeInfo;
2749 static RuntimeInvokeInfo*
2750 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2752 MonoMethod *invoke;
2753 RuntimeInvokeInfo *info;
2755 info = g_new0 (RuntimeInvokeInfo, 1);
2756 info->compiled_method = compiled_method;
2757 info->use_interp = use_interp;
2758 if (mono_llvm_only && method->string_ctor)
2759 info->sig = mono_marshal_get_string_ctor_signature (method);
2760 else
2761 info->sig = mono_method_signature_internal (method);
2763 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2764 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2765 if (!mono_error_ok (error))
2766 return NULL;
2767 g_assert (info->vtable);
2769 MonoMethodSignature *sig = info->sig;
2770 MonoType *ret_type;
2773 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2774 * in full-aot mode, so we use a slower, but more generic wrapper if
2775 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2777 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2778 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2779 gboolean supported = TRUE;
2780 int i;
2782 if (method->string_ctor)
2783 sig = mono_marshal_get_string_ctor_signature (method);
2785 for (i = 0; i < sig->param_count; ++i) {
2786 MonoType *t = sig->params [i];
2788 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
2789 supported = FALSE;
2792 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2793 supported = FALSE;
2795 if (supported) {
2796 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2797 if (mini_debug_options.dyn_runtime_invoke)
2798 g_assert (info->dyn_call_info);
2801 #endif
2803 ret_type = sig->ret;
2804 switch (ret_type->type) {
2805 case MONO_TYPE_VOID:
2806 break;
2807 case MONO_TYPE_I1:
2808 case MONO_TYPE_U1:
2809 case MONO_TYPE_I2:
2810 case MONO_TYPE_U2:
2811 case MONO_TYPE_I4:
2812 case MONO_TYPE_U4:
2813 case MONO_TYPE_I:
2814 case MONO_TYPE_U:
2815 case MONO_TYPE_I8:
2816 case MONO_TYPE_U8:
2817 case MONO_TYPE_BOOLEAN:
2818 case MONO_TYPE_CHAR:
2819 case MONO_TYPE_R4:
2820 case MONO_TYPE_R8:
2821 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2822 break;
2823 case MONO_TYPE_PTR:
2824 info->ret_box_class = mono_defaults.int_class;
2825 break;
2826 case MONO_TYPE_STRING:
2827 case MONO_TYPE_CLASS:
2828 case MONO_TYPE_ARRAY:
2829 case MONO_TYPE_SZARRAY:
2830 case MONO_TYPE_OBJECT:
2831 break;
2832 case MONO_TYPE_GENERICINST:
2833 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2834 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2835 break;
2836 case MONO_TYPE_VALUETYPE:
2837 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2838 break;
2839 default:
2840 g_assert_not_reached ();
2841 break;
2844 if (info->use_interp)
2845 return info;
2847 if (!info->dyn_call_info) {
2848 if (mono_llvm_only) {
2849 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2850 g_assert_not_reached ();
2851 #endif
2852 info->gsharedvt_invoke = TRUE;
2853 if (!callee_gsharedvt) {
2854 /* Invoke a gsharedvt out wrapper instead */
2855 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2856 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2858 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2859 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2861 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2862 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2863 g_free (wrapper_sig);
2865 info->compiled_method = mono_jit_compile_method (wrapper, error);
2866 if (!mono_error_ok (error)) {
2867 g_free (info);
2868 return NULL;
2870 } else {
2871 /* Gsharedvt methods can be invoked the same way */
2872 /* The out wrapper has the same signature as the compiled gsharedvt method */
2873 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2875 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
2877 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2878 g_free (wrapper_sig);
2881 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2882 if (!mono_error_ok (error)) {
2883 g_free (info);
2884 return NULL;
2888 return info;
2891 static MonoObject*
2892 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2894 MonoMethodSignature *sig = info->sig;
2895 MonoDomain *domain = mono_domain_get ();
2896 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2897 gpointer *args;
2898 gpointer retval_ptr;
2899 guint8 retval [256];
2900 gpointer *param_refs;
2901 int i, pindex;
2903 error_init (error);
2905 g_assert (info->gsharedvt_invoke);
2908 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2909 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2910 * signatures, so we only have to generate runtime invoke wrappers for these
2911 * signatures.
2912 * This code also handles invocation of gsharedvt methods directly, no
2913 * out wrappers are used in that case.
2915 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2916 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2917 pindex = 0;
2919 * The runtime invoke wrappers expects pointers to primitive types, so have to
2920 * use indirections.
2922 if (sig->hasthis)
2923 args [pindex ++] = &obj;
2924 if (sig->ret->type != MONO_TYPE_VOID) {
2925 retval_ptr = (gpointer)&retval;
2926 args [pindex ++] = &retval_ptr;
2928 for (i = 0; i < sig->param_count; ++i) {
2929 MonoType *t = sig->params [i];
2931 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
2932 MonoClass *klass = mono_class_from_mono_type_internal (t);
2933 guint8 *nullable_buf;
2934 int size;
2936 size = mono_class_value_size (klass, NULL);
2937 nullable_buf = g_alloca (size);
2938 g_assert (nullable_buf);
2940 /* The argument pointed to by params [i] is either a boxed vtype or null */
2941 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2942 params [i] = nullable_buf;
2945 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2946 param_refs [i] = params [i];
2947 params [i] = &(param_refs [i]);
2949 args [pindex ++] = &params [i];
2951 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2952 args [pindex ++] = &info->wrapper_arg;
2954 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2956 runtime_invoke (NULL, args, exc, info->compiled_method);
2957 if (exc && *exc)
2958 return NULL;
2960 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2961 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2962 else
2963 return *(MonoObject**)retval;
2967 * mono_jit_runtime_invoke:
2968 * \param method: the method to invoke
2969 * \param obj: this pointer
2970 * \param params: array of parameter values.
2971 * \param exc: Set to the exception raised in the managed method.
2972 * \param error: error or caught exception object
2973 * If \p exc is NULL, \p error is thrown instead.
2974 * If coop is enabled, \p exc argument is ignored -
2975 * all exceptions are caught and propagated through \p error
2977 static MonoObject*
2978 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2980 MonoMethod *invoke, *callee;
2981 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2982 MonoDomain *domain = mono_domain_get ();
2983 MonoJitDomainInfo *domain_info;
2984 RuntimeInvokeInfo *info, *info2;
2985 MonoJitInfo *ji = NULL;
2986 gboolean callee_gsharedvt = FALSE;
2988 if (mono_ee_features.force_use_interpreter)
2989 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
2991 error_init (error);
2992 if (exc)
2993 *exc = NULL;
2995 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2996 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2997 return NULL;
3000 domain_info = domain_jit_info (domain);
3002 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3004 if (!info) {
3005 if (mono_security_core_clr_enabled ()) {
3007 * This might be redundant since mono_class_vtable () already does this,
3008 * but keep it just in case for moonlight.
3010 mono_class_setup_vtable (method->klass);
3011 if (mono_class_has_failure (method->klass)) {
3012 mono_error_set_for_class_failure (error, method->klass);
3013 if (exc)
3014 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3015 return NULL;
3019 gpointer compiled_method;
3021 callee = method;
3022 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3023 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3025 * Array Get/Set/Address methods. The JIT implements them using inline code
3026 * inside the runtime invoke wrappers, so no need to compile them.
3028 if (mono_aot_only) {
3030 * Call a wrapper, since the runtime invoke wrapper was not generated.
3032 MonoMethod *wrapper;
3034 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3035 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3036 callee = wrapper;
3037 } else {
3038 callee = NULL;
3042 gboolean use_interp = FALSE;
3044 if (callee) {
3045 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3046 if (!compiled_method) {
3047 g_assert (!mono_error_ok (error));
3049 if (mono_use_interpreter)
3050 use_interp = TRUE;
3051 else
3052 return NULL;
3053 } else {
3054 if (mono_llvm_only) {
3055 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3056 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3057 if (callee_gsharedvt)
3058 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3061 if (!callee_gsharedvt)
3062 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3064 } else {
3065 compiled_method = NULL;
3068 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3069 if (!mono_error_ok (error))
3070 return NULL;
3072 mono_domain_lock (domain);
3073 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3074 mono_domain_unlock (domain);
3075 if (info2) {
3076 g_free (info);
3077 info = info2;
3082 * We need this here because mono_marshal_get_runtime_invoke can place
3083 * the helper method in System.Object and not the target class.
3085 if (!mono_runtime_class_init_full (info->vtable, error)) {
3086 if (exc)
3087 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3088 return NULL;
3091 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3092 we always catch the exception and propagate it through the MonoError */
3093 gboolean catchExcInMonoError =
3094 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3095 MonoObject *invoke_exc = NULL;
3096 if (catchExcInMonoError)
3097 exc = &invoke_exc;
3099 /* The wrappers expect this to be initialized to NULL */
3100 if (exc)
3101 *exc = NULL;
3103 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3104 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3105 if (info->dyn_call_info) {
3106 if (!dyn_runtime_invoke) {
3107 mono_domain_lock (domain);
3109 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3110 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3111 if (!dyn_runtime_invoke && mono_use_interpreter) {
3112 info->use_interp = TRUE;
3113 info->dyn_call_info = NULL;
3114 } else if (!mono_error_ok (error)) {
3115 mono_domain_unlock (domain);
3116 return NULL;
3118 mono_domain_unlock (domain);
3121 if (info->dyn_call_info) {
3122 MonoMethodSignature *sig = mono_method_signature_internal (method);
3123 gpointer *args;
3124 int i, pindex, buf_size;
3125 guint8 *buf;
3126 guint8 retval [256];
3128 /* Convert the arguments to the format expected by start_dyn_call () */
3129 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3130 pindex = 0;
3131 if (sig->hasthis)
3132 args [pindex ++] = &obj;
3133 for (i = 0; i < sig->param_count; ++i) {
3134 MonoType *t = sig->params [i];
3136 if (t->byref) {
3137 args [pindex ++] = &params [i];
3138 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3139 args [pindex ++] = &params [i];
3140 } else {
3141 args [pindex ++] = params [i];
3145 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3147 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3148 buf = g_alloca (buf_size);
3149 memset (buf, 0, buf_size);
3150 g_assert (buf);
3152 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3154 dyn_runtime_invoke (buf, exc, info->compiled_method);
3155 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3157 if (catchExcInMonoError && *exc != NULL) {
3158 mono_error_set_exception_instance (error, (MonoException*) *exc);
3159 return NULL;
3162 if (info->ret_box_class)
3163 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3164 else
3165 return *(MonoObject**)retval;
3167 #endif
3169 MonoObject *result;
3171 if (info->use_interp) {
3172 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3173 return_val_if_nok (error, NULL);
3174 } else if (mono_llvm_only) {
3175 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3176 if (!is_ok (error))
3177 return NULL;
3178 } else {
3179 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3181 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3183 if (catchExcInMonoError && *exc != NULL) {
3184 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3185 mono_error_set_exception_instance (error, (MonoException*) *exc);
3187 return result;
3190 typedef struct {
3191 MonoVTable *vtable;
3192 int slot;
3193 } IMTTrampInfo;
3195 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
3198 * mini_llvmonly_initial_imt_tramp:
3200 * This function is called the first time a call is made through an IMT trampoline.
3201 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
3203 static gpointer
3204 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3206 IMTTrampInfo *info = (IMTTrampInfo*)arg;
3207 IMTTrampFunc **imt;
3208 IMTTrampFunc *ftndesc;
3209 IMTTrampFunc func;
3211 mono_vtable_build_imt_slot (info->vtable, info->slot);
3213 imt = (IMTTrampFunc**)info->vtable;
3214 imt -= MONO_IMT_SIZE;
3216 /* Return what the real IMT trampoline returns */
3217 ftndesc = imt [info->slot];
3218 func = ftndesc [0];
3220 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
3221 /* Happens when the imt slot contains only a generic virtual method */
3222 return NULL;
3223 return func ((gpointer *)ftndesc [1], imt_method);
3226 /* This is called indirectly through an imt slot. */
3227 static gpointer
3228 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3230 int i = 0;
3232 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
3233 while (arg [i] && arg [i] != imt_method)
3234 i += 2;
3235 g_assert (arg [i]);
3237 return arg [i + 1];
3240 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
3241 static gpointer
3242 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
3244 //g_assert (arg [0] == imt_method);
3245 return arg [1];
3248 static gpointer
3249 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
3251 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
3252 if (arg [0] == imt_method)
3253 return arg [1];
3254 else
3255 return arg [3];
3258 static gpointer
3259 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
3261 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
3262 if (arg [0] == imt_method)
3263 return arg [1];
3264 else if (arg [2] == imt_method)
3265 return arg [3];
3266 else
3267 return arg [5];
3271 * A version of the imt trampoline used for generic virtual/variant iface methods.
3272 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
3273 * in the search table. The original JIT code had a 'fallback' trampoline it could
3274 * call, but we can't do that, so we just return NULL, and the compiled code
3275 * will handle it.
3277 static gpointer
3278 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3280 int i = 0;
3282 while (arg [i] && arg [i] != imt_method)
3283 i += 2;
3284 if (!arg [i])
3285 return NULL;
3287 return arg [i + 1];
3290 static gpointer
3291 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
3293 gpointer *buf;
3294 gpointer *res;
3295 int i, index, real_count;
3296 gboolean virtual_generic = FALSE;
3299 * Create an array which is passed to the imt trampoline functions.
3300 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
3303 real_count = 0;
3304 for (i = 0; i < count; ++i) {
3305 MonoIMTCheckItem *item = imt_entries [i];
3307 if (item->is_equals)
3308 real_count ++;
3309 if (item->has_target_code)
3310 virtual_generic = TRUE;
3314 * Initialize all vtable entries reachable from this imt slot, so the compiled
3315 * code doesn't have to check it.
3317 for (i = 0; i < count; ++i) {
3318 MonoIMTCheckItem *item = imt_entries [i];
3319 int vt_slot;
3321 if (!item->is_equals || item->has_target_code)
3322 continue;
3323 vt_slot = item->value.vtable_slot;
3324 mono_init_vtable_slot (vtable, vt_slot);
3327 /* Save the entries into an array */
3328 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
3329 index = 0;
3330 for (i = 0; i < count; ++i) {
3331 MonoIMTCheckItem *item = imt_entries [i];
3333 if (!item->is_equals)
3334 continue;
3336 g_assert (item->key);
3337 buf [(index * 2)] = item->key;
3338 if (item->has_target_code)
3339 buf [(index * 2) + 1] = item->value.target_code;
3340 else
3341 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
3342 index ++;
3344 buf [(index * 2)] = NULL;
3345 buf [(index * 2) + 1] = fail_tramp;
3348 * Return a function descriptor for a C function with 'buf' as its argument.
3349 * It will by called by JITted code.
3351 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
3352 switch (real_count) {
3353 case 1:
3354 res [0] = (gpointer)mono_llvmonly_imt_tramp_1;
3355 break;
3356 case 2:
3357 res [0] = (gpointer)mono_llvmonly_imt_tramp_2;
3358 break;
3359 case 3:
3360 res [0] = (gpointer)mono_llvmonly_imt_tramp_3;
3361 break;
3362 default:
3363 res [0] = (gpointer)mono_llvmonly_imt_tramp;
3364 break;
3366 if (virtual_generic || fail_tramp)
3367 res [0] = (gpointer)mono_llvmonly_fallback_imt_tramp;
3368 res [1] = buf;
3370 return res;
3373 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3375 MonoException *exc = NULL;
3376 MonoJitInfo *ji;
3377 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3378 MONO_SIG_HANDLER_GET_CONTEXT;
3380 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3382 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3384 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3385 if (mono_arch_is_int_overflow (ctx, info))
3387 * The spec says this throws ArithmeticException, but MS throws the derived
3388 * OverflowException.
3390 exc = mono_get_exception_overflow ();
3391 else
3392 exc = mono_get_exception_divide_by_zero ();
3393 #else
3394 exc = mono_get_exception_divide_by_zero ();
3395 #endif
3397 if (!ji) {
3398 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3399 goto exit;
3401 mono_handle_native_crash ("SIGFPE", ctx, info);
3402 if (mono_do_crash_chaining) {
3403 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3404 goto exit;
3408 mono_arch_handle_exception (ctx, exc);
3410 exit:
3411 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3414 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3416 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3417 MONO_SIG_HANDLER_GET_CONTEXT;
3419 if (mono_runtime_get_no_exec ())
3420 exit (1);
3423 mono_handle_native_crash ("SIGILL", ctx, info);
3424 if (mono_do_crash_chaining) {
3425 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3426 return;
3429 g_assert_not_reached ();
3432 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3434 #define HAVE_SIG_INFO
3435 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3437 #ifdef MONO_SIG_HANDLER_DEBUG
3438 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3439 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3440 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3441 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3442 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3443 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3444 #endif
3446 #endif
3448 static gboolean
3449 is_addr_implicit_null_check (void *addr)
3451 /* implicit null checks are only expected to work on the first page. larger
3452 * offsets are expected to have an explicit null check */
3453 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3456 // This function is separate from mono_sigsegv_signal_handler
3457 // so debug_fault_addr can be seen in debugger stacks.
3458 #ifdef MONO_SIG_HANDLER_DEBUG
3459 MONO_NEVER_INLINE
3460 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3461 #else
3462 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3463 #endif
3465 MonoJitInfo *ji;
3466 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3467 gpointer fault_addr = NULL;
3468 #ifdef HAVE_SIG_INFO
3469 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3470 #else
3471 void *info = NULL;
3472 #endif
3473 MONO_SIG_HANDLER_GET_CONTEXT;
3475 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3476 if (mono_arch_is_single_step_event (info, ctx)) {
3477 mini_get_dbg_callbacks ()->single_step_event (ctx);
3478 return;
3479 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3480 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3481 return;
3483 #endif
3485 #if defined(HAVE_SIG_INFO)
3486 #if !defined(HOST_WIN32)
3487 fault_addr = info->si_addr;
3488 if (mono_aot_is_pagefault (info->si_addr)) {
3489 mono_aot_handle_pagefault (info->si_addr);
3490 return;
3492 #endif
3494 /* The thread might no be registered with the runtime */
3495 if (!mono_domain_get () || !jit_tls) {
3496 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3497 return;
3498 mono_handle_native_crash ("SIGSEGV", ctx, info);
3499 if (mono_do_crash_chaining) {
3500 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3501 return;
3504 #endif
3506 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3508 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3509 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3510 return;
3512 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3513 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3514 fault_addr = info->si_addr;
3515 if (fault_addr == NULL) {
3516 MonoContext mctx;
3518 mono_sigctx_to_monoctx (ctx, &mctx);
3520 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3522 #endif
3524 if (jit_tls->stack_size &&
3525 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3527 * The hard-guard page has been hit: there is not much we can do anymore
3528 * Print a hopefully clear message and abort.
3530 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3531 g_assert_not_reached ();
3532 } else {
3533 /* The original handler might not like that it is executed on an altstack... */
3534 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3535 return;
3537 if (is_addr_implicit_null_check (info->si_addr)) {
3538 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3539 } else {
3540 mono_handle_native_crash ("SIGSEGV", ctx, info);
3543 #else
3545 if (!ji) {
3546 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3547 return;
3549 mono_handle_native_crash ("SIGSEGV", ctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3551 if (mono_do_crash_chaining) {
3552 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3553 return;
3557 if (is_addr_implicit_null_check (fault_addr)) {
3558 mono_arch_handle_exception (ctx, NULL);
3559 } else {
3560 mono_handle_native_crash ("SIGSEGV", ctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3562 #endif
3565 #ifdef MONO_SIG_HANDLER_DEBUG
3567 // This function is separate from mono_sigsegv_signal_handler_debug
3568 // so debug_fault_addr can be seen in debugger stacks.
3569 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3571 #ifdef HOST_WIN32
3572 gpointer const debug_fault_addr = (gpointer)_info->ExceptionRecord->ExceptionInformation [1];
3573 #elif defined (HAVE_SIG_INFO)
3574 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3575 #else
3576 #error No extra parameter is passed, not even 0, to avoid any confusion.
3577 #endif
3578 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3581 #endif // MONO_SIG_HANDLER_DEBUG
3583 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3585 MonoException *exc;
3586 MONO_SIG_HANDLER_GET_CONTEXT;
3588 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3590 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3592 mono_arch_handle_exception (ctx, exc);
3594 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3597 #ifndef DISABLE_REMOTING
3598 /* mono_jit_create_remoting_trampoline:
3599 * @method: pointer to the method info
3601 * Creates a trampoline which calls the remoting functions. This
3602 * is used in the vtable of transparent proxies.
3604 * Returns: a pointer to the newly created code
3606 static gpointer
3607 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3609 MonoMethod *nm;
3610 guint8 *addr = NULL;
3612 error_init (error);
3614 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3615 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3616 domain, NULL);
3619 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3620 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3621 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3622 else
3623 nm = method;
3624 return_val_if_nok (error, NULL);
3625 addr = (guint8 *)mono_compile_method_checked (nm, error);
3626 return_val_if_nok (error, NULL);
3627 return mono_get_addr_from_ftnptr (addr);
3629 #endif
3631 static G_GNUC_UNUSED void
3632 no_imt_trampoline (void)
3634 g_assert_not_reached ();
3637 static G_GNUC_UNUSED void
3638 no_vcall_trampoline (void)
3640 g_assert_not_reached ();
3643 static gpointer *vtable_trampolines;
3644 static int vtable_trampolines_size;
3646 gpointer
3647 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3649 int index = slot_index + MONO_IMT_SIZE;
3651 if (mono_llvm_only) {
3652 if (slot_index < 0) {
3653 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3654 // FIXME: Memory management
3655 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3656 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3657 info->vtable = vt;
3658 info->slot = index;
3659 ftndesc [0] = (gpointer)mini_llvmonly_initial_imt_tramp;
3660 ftndesc [1] = info;
3661 mono_memory_barrier ();
3662 return ftndesc;
3663 } else {
3664 return NULL;
3668 g_assert (slot_index >= - MONO_IMT_SIZE);
3669 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3670 mono_jit_lock ();
3671 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3672 int new_size;
3673 gpointer new_table;
3675 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3676 while (new_size <= index)
3677 new_size *= 2;
3678 new_table = g_new0 (gpointer, new_size);
3680 if (vtable_trampolines)
3681 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3682 g_free (vtable_trampolines);
3683 mono_memory_barrier ();
3684 vtable_trampolines = (void **)new_table;
3685 vtable_trampolines_size = new_size;
3687 mono_jit_unlock ();
3690 if (!vtable_trampolines [index])
3691 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3692 return vtable_trampolines [index];
3695 static gpointer
3696 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3698 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3701 static gboolean
3702 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3704 if (mono_llvm_only)
3705 return FALSE;
3707 gpointer *imt = (gpointer*)vt;
3708 imt -= MONO_IMT_SIZE;
3710 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3713 static gboolean
3714 is_callee_gsharedvt_variable (gpointer addr)
3716 MonoJitInfo *ji;
3717 gboolean callee_gsharedvt;
3719 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3720 g_assert (ji);
3721 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3722 if (callee_gsharedvt)
3723 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3724 return callee_gsharedvt;
3727 gpointer
3728 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3730 gpointer arg = NULL;
3732 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3733 arg = mini_method_get_rgctx (method);
3736 * Avoid adding gsharedvt in wrappers since they might not exist if
3737 * this delegate is called through a gsharedvt delegate invoke wrapper.
3738 * Instead, encode that the method is gsharedvt in del->extra_arg,
3739 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3741 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3742 g_assert ((((gsize)arg) & 1) == 0);
3743 arg = (gpointer)(((gsize)arg) | 1);
3745 return arg;
3748 void
3749 mini_init_delegate (MonoDelegate *del)
3751 if (mono_use_interpreter)
3752 mini_get_interp_callbacks ()->init_delegate (del);
3753 else if (mono_llvm_only)
3754 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3757 char*
3758 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3760 int abs_offset;
3762 abs_offset = offset;
3763 if (abs_offset < 0)
3764 abs_offset = - abs_offset;
3765 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3768 gpointer
3769 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3771 gboolean is_virtual_generic, is_interface, load_imt_reg;
3772 int offset, idx;
3774 static guint8 **cache = NULL;
3775 static int cache_size = 0;
3777 if (!method)
3778 return NULL;
3780 if (MONO_TYPE_ISSTRUCT (sig->ret))
3781 return NULL;
3783 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3784 is_interface = mono_class_is_interface (method->klass);
3785 load_imt_reg = is_virtual_generic || is_interface;
3787 if (is_interface)
3788 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3789 else
3790 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3792 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3793 g_assert (idx >= 0);
3795 /* Resize the cache to idx + 1 */
3796 if (cache_size < idx + 1) {
3797 mono_jit_lock ();
3798 if (cache_size < idx + 1) {
3799 guint8 **new_cache;
3800 int new_cache_size = idx + 1;
3802 new_cache = g_new0 (guint8*, new_cache_size);
3803 if (cache)
3804 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3805 g_free (cache);
3807 mono_memory_barrier ();
3808 cache = new_cache;
3809 cache_size = new_cache_size;
3811 mono_jit_unlock ();
3814 if (cache [idx])
3815 return cache [idx];
3817 /* FIXME Support more cases */
3818 if (mono_ee_features.use_aot_trampolines) {
3819 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3820 g_assert (cache [idx]);
3821 } else {
3822 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3824 return cache [idx];
3828 * mini_parse_debug_option:
3829 * @option: The option to parse.
3831 * Parses debug options for the mono runtime. The options are the same as for
3832 * the MONO_DEBUG environment variable.
3835 gboolean
3836 mini_parse_debug_option (const char *option)
3838 // Empty string is ok as consequence of appending ",foo"
3839 // without first checking for empty.
3840 if (*option == 0)
3841 return TRUE;
3843 if (!strcmp (option, "handle-sigint"))
3844 mini_debug_options.handle_sigint = TRUE;
3845 else if (!strcmp (option, "keep-delegates"))
3846 mini_debug_options.keep_delegates = TRUE;
3847 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3848 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3849 else if (!strcmp (option, "collect-pagefault-stats"))
3850 mini_debug_options.collect_pagefault_stats = TRUE;
3851 else if (!strcmp (option, "break-on-unverified"))
3852 mini_debug_options.break_on_unverified = TRUE;
3853 else if (!strcmp (option, "no-gdb-backtrace"))
3854 mini_debug_options.no_gdb_backtrace = TRUE;
3855 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3856 mini_debug_options.suspend_on_native_crash = TRUE;
3857 else if (!strcmp (option, "suspend-on-exception"))
3858 mini_debug_options.suspend_on_exception = TRUE;
3859 else if (!strcmp (option, "suspend-on-unhandled"))
3860 mini_debug_options.suspend_on_unhandled = TRUE;
3861 else if (!strcmp (option, "dont-free-domains"))
3862 mono_dont_free_domains = TRUE;
3863 else if (!strcmp (option, "dyn-runtime-invoke"))
3864 mini_debug_options.dyn_runtime_invoke = TRUE;
3865 else if (!strcmp (option, "gdb"))
3866 mini_debug_options.gdb = TRUE;
3867 else if (!strcmp (option, "lldb"))
3868 mini_debug_options.lldb = TRUE;
3869 else if (!strcmp (option, "explicit-null-checks"))
3870 mini_debug_options.explicit_null_checks = TRUE;
3871 else if (!strcmp (option, "gen-seq-points"))
3872 mini_debug_options.gen_sdb_seq_points = TRUE;
3873 else if (!strcmp (option, "gen-compact-seq-points"))
3874 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3875 else if (!strcmp (option, "no-compact-seq-points"))
3876 mini_debug_options.no_seq_points_compact_data = TRUE;
3877 else if (!strcmp (option, "single-imm-size"))
3878 mini_debug_options.single_imm_size = TRUE;
3879 else if (!strcmp (option, "init-stacks"))
3880 mini_debug_options.init_stacks = TRUE;
3881 else if (!strcmp (option, "casts"))
3882 mini_debug_options.better_cast_details = TRUE;
3883 else if (!strcmp (option, "soft-breakpoints"))
3884 mini_debug_options.soft_breakpoints = TRUE;
3885 else if (!strcmp (option, "check-pinvoke-callconv"))
3886 mini_debug_options.check_pinvoke_callconv = TRUE;
3887 else if (!strcmp (option, "use-fallback-tls"))
3888 mini_debug_options.use_fallback_tls = TRUE;
3889 else if (!strcmp (option, "debug-domain-unload"))
3890 mono_enable_debug_domain_unload (TRUE);
3891 else if (!strcmp (option, "partial-sharing"))
3892 mono_set_partial_sharing_supported (TRUE);
3893 else if (!strcmp (option, "align-small-structs"))
3894 mono_align_small_structs = TRUE;
3895 else if (!strcmp (option, "native-debugger-break"))
3896 mini_debug_options.native_debugger_break = TRUE;
3897 else if (!strcmp (option, "disable_omit_fp"))
3898 mini_debug_options.disable_omit_fp = TRUE;
3899 // This is an internal testing feature.
3900 // Every tail. encountered is required to be optimized.
3901 // It is asserted.
3902 else if (!strcmp (option, "test-tailcall-require"))
3903 mini_debug_options.test_tailcall_require = TRUE;
3904 else if (!strcmp (option, "verbose-gdb"))
3905 mini_debug_options.verbose_gdb = TRUE;
3906 else if (!strncmp (option, "thread-dump-dir=", 16))
3907 mono_set_thread_dump_dir(g_strdup(option + 16));
3908 else if (!strncmp (option, "aot-skip=", 9)) {
3909 mini_debug_options.aot_skip_set = TRUE;
3910 mini_debug_options.aot_skip = atoi (option + 9);
3911 } else
3912 return FALSE;
3914 return TRUE;
3917 static void
3918 mini_parse_debug_options (void)
3920 char *options = g_getenv ("MONO_DEBUG");
3921 gchar **args, **ptr;
3923 if (!options)
3924 return;
3926 args = g_strsplit (options, ",", -1);
3927 g_free (options);
3929 for (ptr = args; ptr && *ptr; ptr++) {
3930 const char *arg = *ptr;
3932 if (!mini_parse_debug_option (arg)) {
3933 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3934 // test-tailcall-require is also accepted but not documented.
3935 // empty string is also accepted and ignored as a consequence
3936 // of appending ",foo" without checking for empty.
3937 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");
3938 exit (1);
3942 g_strfreev (args);
3945 MonoDebugOptions *
3946 mini_get_debug_options (void)
3948 return &mini_debug_options;
3951 static gpointer
3952 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3954 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3955 gpointer* desc = NULL;
3957 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3958 return desc;
3959 #if defined(__mono_ppc64__)
3960 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3962 desc [0] = addr;
3963 desc [1] = NULL;
3964 desc [2] = NULL;
3965 # endif
3966 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3967 return desc;
3968 #else
3969 return addr;
3970 #endif
3973 static gpointer
3974 mini_get_addr_from_ftnptr (gpointer descr)
3976 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3977 return *(gpointer*)descr;
3978 #else
3979 return descr;
3980 #endif
3983 static void
3984 register_jit_stats (void)
3986 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3987 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3988 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3989 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3990 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
3991 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3992 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3993 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);
3994 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3995 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3996 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3997 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3998 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3999 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
4000 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
4001 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
4002 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
4003 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
4004 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
4005 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
4006 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
4007 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
4008 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
4009 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
4010 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
4011 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
4012 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
4013 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
4014 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
4015 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
4016 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
4017 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
4018 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
4019 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
4020 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
4021 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
4022 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
4023 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
4024 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
4025 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
4026 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
4027 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
4028 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
4029 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
4030 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
4031 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
4032 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
4033 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
4034 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
4035 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
4036 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
4037 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
4038 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
4039 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
4040 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
4041 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
4042 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
4043 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
4044 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
4045 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
4046 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
4047 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
4050 static void runtime_invoke_info_free (gpointer value);
4052 static gint
4053 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
4055 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
4056 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
4058 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
4061 static guint
4062 class_method_pair_hash (gconstpointer data)
4064 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
4066 return (gsize)pair->klass ^ (gsize)pair->method;
4069 static void
4070 mini_create_jit_domain_info (MonoDomain *domain)
4072 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
4074 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4075 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4076 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
4077 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4078 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
4079 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
4080 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
4081 info->jump_target_hash = g_hash_table_new (NULL, NULL);
4082 mono_jit_code_hash_init (&info->interp_code_hash);
4084 domain->runtime_info = info;
4087 static void
4088 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
4090 MonoJumpList *jlist = (MonoJumpList *)value;
4091 g_slist_free ((GSList*)jlist->list);
4094 static void
4095 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
4097 GSList *list = (GSList *)value;
4098 g_slist_free (list);
4101 static void
4102 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
4104 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
4105 mono_code_manager_destroy (di->code_mp);
4106 g_free (di);
4109 static void
4110 runtime_invoke_info_free (gpointer value)
4112 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
4114 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4115 if (info->dyn_call_info)
4116 mono_arch_dyn_call_free (info->dyn_call_info);
4117 #endif
4118 g_free (info);
4121 static void
4122 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
4124 g_slist_free ((GSList*)value);
4127 static void
4128 mini_free_jit_domain_info (MonoDomain *domain)
4130 MonoJitDomainInfo *info = domain_jit_info (domain);
4132 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
4133 g_hash_table_destroy (info->jump_target_hash);
4134 if (info->jump_target_got_slot_hash) {
4135 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
4136 g_hash_table_destroy (info->jump_target_got_slot_hash);
4138 if (info->dynamic_code_hash) {
4139 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
4140 g_hash_table_destroy (info->dynamic_code_hash);
4142 g_hash_table_destroy (info->method_code_hash);
4143 g_hash_table_destroy (info->jump_trampoline_hash);
4144 g_hash_table_destroy (info->jit_trampoline_hash);
4145 g_hash_table_destroy (info->delegate_trampoline_hash);
4146 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
4147 g_hash_table_destroy (info->mrgctx_hash);
4148 g_hash_table_destroy (info->method_rgctx_hash);
4149 g_hash_table_destroy (info->interp_method_pointer_hash);
4150 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
4151 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
4152 g_hash_table_destroy (info->seq_points);
4153 g_hash_table_destroy (info->arch_seq_points);
4154 if (info->agent_info)
4155 mini_get_dbg_callbacks ()->free_domain_info (domain);
4156 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
4157 if (info->llvm_jit_callees) {
4158 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
4159 g_hash_table_destroy (info->llvm_jit_callees);
4161 mono_internal_hash_table_destroy (&info->interp_code_hash);
4162 #ifdef ENABLE_LLVM
4163 mono_llvm_free_domain_info (domain);
4164 #endif
4166 g_free (domain->runtime_info);
4167 domain->runtime_info = NULL;
4170 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4172 static void
4173 code_manager_chunk_new (void *chunk, int size)
4175 mono_arch_code_chunk_new (chunk, size);
4178 static void
4179 code_manager_chunk_destroy (void *chunk)
4181 mono_arch_code_chunk_destroy (chunk);
4184 #endif
4186 #ifdef ENABLE_LLVM
4187 static gboolean
4188 llvm_init_inner (void)
4190 if (!mono_llvm_load (NULL))
4191 return FALSE;
4193 mono_llvm_init ();
4194 return TRUE;
4196 #endif
4199 * mini_llvm_init:
4201 * Load and initialize LLVM support.
4202 * Return TRUE on success.
4204 gboolean
4205 mini_llvm_init (void)
4207 #ifdef ENABLE_LLVM
4208 static gboolean llvm_inited;
4209 static gboolean init_result;
4211 mono_loader_lock_if_inited ();
4212 if (!llvm_inited) {
4213 init_result = llvm_init_inner ();
4214 llvm_inited = TRUE;
4216 mono_loader_unlock_if_inited ();
4217 return init_result;
4218 #else
4219 return FALSE;
4220 #endif
4223 void
4224 mini_add_profiler_argument (const char *desc)
4226 if (!profile_options)
4227 profile_options = g_ptr_array_new ();
4229 g_ptr_array_add (profile_options, (gpointer) desc);
4233 static MonoEECallbacks interp_cbs = {0};
4235 void
4236 mini_install_interp_callbacks (MonoEECallbacks *cbs)
4238 memcpy (&interp_cbs, cbs, sizeof (MonoEECallbacks));
4241 MonoEECallbacks *
4242 mini_get_interp_callbacks (void)
4244 return &interp_cbs;
4247 static MonoDebuggerCallbacks dbg_cbs;
4249 void
4250 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4252 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4253 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4256 MonoDebuggerCallbacks*
4257 mini_get_dbg_callbacks (void)
4259 return &dbg_cbs;
4263 mono_ee_api_version (void)
4265 return MONO_EE_API_VERSION;
4268 void
4269 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4271 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4274 MonoDomain *
4275 mini_init (const char *filename, const char *runtime_version)
4277 ERROR_DECL (error);
4278 MonoDomain *domain;
4279 MonoRuntimeCallbacks callbacks;
4280 MonoThreadInfoRuntimeCallbacks ticallbacks;
4281 MonoCodeManagerCallbacks code_manager_callbacks;
4283 MONO_VES_INIT_BEGIN ();
4285 CHECKED_MONO_INIT ();
4287 #if defined(__linux__)
4288 if (access ("/proc/self/maps", F_OK) != 0) {
4289 g_print ("Mono requires /proc to be mounted.\n");
4290 exit (1);
4292 #endif
4294 mono_interp_stub_init ();
4295 #ifndef DISABLE_INTERPRETER
4296 if (mono_use_interpreter)
4297 mono_ee_interp_init (mono_interp_opts_string);
4298 #endif
4300 mono_debugger_agent_stub_init ();
4301 #ifndef DISABLE_SDB
4302 mono_debugger_agent_init ();
4303 #endif
4305 if (sdb_options)
4306 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4308 mono_os_mutex_init_recursive (&jit_mutex);
4310 mono_cross_helpers_run ();
4312 mono_counters_init ();
4314 mini_jit_init ();
4316 mini_jit_init_job_control ();
4318 /* Happens when using the embedding interface */
4319 if (!default_opt_set)
4320 default_opt = mono_parse_default_optimizations (NULL);
4322 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4323 if (mono_aot_only)
4324 mono_set_generic_sharing_vt_supported (TRUE);
4325 #else
4326 if (mono_llvm_only)
4327 mono_set_generic_sharing_vt_supported (TRUE);
4328 #endif
4330 mono_tls_init_runtime_keys ();
4332 if (!global_codeman)
4333 global_codeman = mono_code_manager_new ();
4335 memset (&callbacks, 0, sizeof (callbacks));
4336 callbacks.create_ftnptr = mini_create_ftnptr;
4337 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4338 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4339 callbacks.set_cast_details = mono_set_cast_details;
4340 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4341 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4342 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4343 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4344 callbacks.imt_entry_inited = mini_imt_entry_inited;
4345 callbacks.init_delegate = mini_init_delegate;
4346 #define JIT_INVOKE_WORKS
4347 #ifdef JIT_INVOKE_WORKS
4348 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4349 #endif
4350 #define JIT_TRAMPOLINES_WORK
4351 #ifdef JIT_TRAMPOLINES_WORK
4352 callbacks.compile_method = mono_jit_compile_method;
4353 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4354 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4355 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4356 callbacks.free_method = mono_jit_free_method;
4357 #ifndef DISABLE_REMOTING
4358 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4359 #endif
4360 #endif
4361 #ifndef DISABLE_REMOTING
4362 if (mono_use_interpreter)
4363 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4364 #endif
4365 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4367 #ifndef DISABLE_CRASH_REPORTING
4368 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4369 #endif
4371 mono_install_callbacks (&callbacks);
4373 memset (&ticallbacks, 0, sizeof (ticallbacks));
4374 ticallbacks.setup_async_callback = mono_setup_async_callback;
4375 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
4376 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
4377 ticallbacks.thread_state_init = mono_thread_state_init;
4379 #ifndef HOST_WIN32
4380 mono_w32handle_init ();
4381 #endif
4383 mono_thread_info_runtime_init (&ticallbacks);
4385 if (g_hasenv ("MONO_DEBUG")) {
4386 mini_parse_debug_options ();
4389 mono_code_manager_init ();
4391 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
4392 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4393 code_manager_callbacks.chunk_new = code_manager_chunk_new;
4394 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
4395 #endif
4396 mono_code_manager_install_callbacks (&code_manager_callbacks);
4398 mono_hwcap_init ();
4400 mono_arch_cpu_init ();
4402 mono_arch_init ();
4404 mono_unwind_init ();
4406 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
4407 mono_lldb_init ("");
4408 mono_dont_free_domains = TRUE;
4411 #ifdef XDEBUG_ENABLED
4412 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4413 if (mono_xdebug) {
4414 mono_xdebug_init (mono_xdebug);
4415 g_free (mono_xdebug);
4416 /* So methods for multiple domains don't have the same address */
4417 mono_dont_free_domains = TRUE;
4418 mono_using_xdebug = TRUE;
4419 } else if (mini_get_debug_options ()->gdb) {
4420 mono_xdebug_init ((char*)"gdb");
4421 mono_dont_free_domains = TRUE;
4422 mono_using_xdebug = TRUE;
4424 #endif
4426 #ifdef ENABLE_LLVM
4427 if (mono_use_llvm) {
4428 if (!mono_llvm_load (NULL)) {
4429 mono_use_llvm = FALSE;
4430 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4433 if (mono_use_llvm)
4434 mono_llvm_init ();
4435 #endif
4437 mono_trampolines_init ();
4439 if (default_opt & MONO_OPT_AOT)
4440 mono_aot_init ();
4442 mini_get_dbg_callbacks ()->init ();
4444 #ifdef TARGET_WASM
4445 mono_wasm_debugger_init ();
4446 #endif
4448 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4449 mono_set_generic_sharing_supported (TRUE);
4450 #endif
4452 mono_thread_info_signals_init ();
4454 #ifndef MONO_CROSS_COMPILE
4455 mono_runtime_install_handlers ();
4456 #endif
4457 mono_threads_install_cleanup (mini_thread_cleanup);
4459 #ifdef JIT_TRAMPOLINES_WORK
4460 mono_install_create_domain_hook (mini_create_jit_domain_info);
4461 mono_install_free_domain_hook (mini_free_jit_domain_info);
4462 #endif
4463 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4464 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4465 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4467 mono_profiler_state.context_enable = mini_profiler_context_enable;
4468 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4469 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4470 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4471 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4472 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4474 if (profile_options)
4475 for (guint i = 0; i < profile_options->len; i++)
4476 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4478 mono_profiler_started ();
4480 if (mini_debug_options.collect_pagefault_stats)
4481 mono_aot_set_make_unreadable (TRUE);
4483 if (runtime_version)
4484 domain = mono_init_version (filename, runtime_version);
4485 else
4486 domain = mono_init_from_assembly (filename, filename);
4488 if (mono_aot_only) {
4489 /* This helps catch code allocation requests */
4490 mono_code_manager_set_read_only (domain->code_mp);
4491 mono_marshal_use_aot_wrappers (TRUE);
4494 if (mono_llvm_only) {
4495 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
4496 mono_set_always_build_imt_trampolines (TRUE);
4497 } else if (mono_aot_only) {
4498 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4499 } else {
4500 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4503 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4504 mono_arch_finish_init ();
4506 mono_icall_init ();
4508 /* This must come after mono_init () in the aot-only case */
4509 mono_exceptions_init ();
4511 /* This should come after mono_init () too */
4512 mini_gc_init ();
4514 #ifndef DISABLE_JIT
4515 mono_create_helper_signatures ();
4516 #endif
4518 register_jit_stats ();
4520 #define JIT_CALLS_WORK
4521 #ifdef JIT_CALLS_WORK
4522 /* Needs to be called here since register_jit_icall depends on it */
4523 mono_marshal_init ();
4525 mono_arch_register_lowlevel_calls ();
4527 register_icalls ();
4529 mono_generic_sharing_init ();
4530 #endif
4532 #ifdef MONO_ARCH_SIMD_INTRINSICS
4533 mono_simd_intrinsics_init ();
4534 #endif
4536 mono_tasklets_init ();
4538 register_trampolines (domain);
4540 if (mono_compile_aot)
4542 * Avoid running managed code when AOT compiling, since the platform
4543 * might only support aot-only execution.
4545 mono_runtime_set_no_exec (TRUE);
4547 mono_mem_account_register_counters ();
4549 #define JIT_RUNTIME_WORKS
4550 #ifdef JIT_RUNTIME_WORKS
4551 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4552 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4553 mono_error_assert_ok (error);
4554 mono_thread_attach (domain);
4555 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4556 #endif
4558 if (mono_profiler_sampling_enabled ())
4559 mono_runtime_setup_stat_profiler ();
4561 MONO_PROFILER_RAISE (runtime_initialized, ());
4563 MONO_VES_INIT_END ();
4565 return domain;
4568 #ifdef MONO_ARCH_EMULATE_FREM
4569 // Wrapper to avoid taking address of overloaded function.
4570 static double
4571 mono_fmod (double a, double b)
4573 return fmod (a, b);
4575 #endif
4577 static void
4578 register_icalls (void)
4580 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4581 ves_icall_get_frame_info);
4582 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4583 ves_icall_get_trace);
4584 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4585 mono_runtime_install_handlers);
4586 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4587 mono_runtime_cleanup_handlers);
4589 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4590 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4591 mini_get_dbg_callbacks ()->unhandled_exception);
4592 #endif
4595 * It's important that we pass `TRUE` as the last argument here, as
4596 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4597 * *did* emit a wrapper, we'd be looking at infinite recursion since
4598 * the wrapper would call the icall which would call the wrapper and
4599 * so on.
4601 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4602 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4603 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4604 register_icall (mono_profiler_raise_exception_clause, "mono_profiler_raise_exception_clause", "void ptr int int object", TRUE);
4606 register_icall (mono_trace_enter_method, "mono_trace_enter_method", "void ptr ptr", TRUE);
4607 register_icall (mono_trace_leave_method, "mono_trace_leave_method", "void ptr ptr", TRUE);
4608 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4609 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4610 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4612 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4613 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4614 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4615 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int ptr object", TRUE);
4616 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4617 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4618 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4619 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4620 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4622 // FIXME: This is broken
4623 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4624 #endif
4626 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4627 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4628 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4629 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4630 register_icall (ves_icall_thread_finish_async_abort, "ves_icall_thread_finish_async_abort", "void", FALSE);
4631 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4632 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4634 if (mono_threads_are_safepoints_enabled ())
4635 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4637 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4638 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4639 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4640 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4641 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4642 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4643 #endif
4644 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4645 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4646 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4647 #endif
4649 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4650 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4651 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4652 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4653 #endif
4655 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4656 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4657 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4658 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4659 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4660 #endif
4662 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4663 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4664 #endif
4666 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4667 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4668 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4669 #endif
4671 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4672 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4673 #endif
4675 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4676 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4677 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4678 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4679 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4680 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4681 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4684 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4685 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4686 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4687 #endif
4689 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4690 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);
4691 #endif
4692 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4693 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4694 #endif
4695 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4696 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4697 #endif
4698 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4699 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);
4700 #endif
4701 #ifdef MONO_ARCH_EMULATE_FREM
4702 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "fmod", FALSE);
4703 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4704 #endif
4706 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4707 if (mono_arch_is_soft_float ()) {
4708 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4709 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4710 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4711 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4712 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4713 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4714 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4715 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4716 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4717 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4718 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4719 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4721 #if TARGET_SIZEOF_VOID_P == 4
4722 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4723 #endif
4725 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4726 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4727 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4728 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4729 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4730 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4731 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4732 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4733 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4734 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4736 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4737 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4738 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4739 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4740 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4742 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4743 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4744 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4745 register_icall (mono_isfinite_double, "mono_isfinite_double", "int32 double", FALSE);
4747 #endif
4748 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4750 #ifdef COMPRESSED_INTERFACE_BITMAP
4751 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4752 #endif
4754 #if SIZEOF_REGISTER == 4
4755 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4756 #else
4757 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4758 #endif
4760 /* other jit icalls */
4761 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4762 register_icall (ves_icall_mono_delegate_ctor_interp, "ves_icall_mono_delegate_ctor_interp", "void object object ptr", FALSE);
4763 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4764 "ptr ptr ptr", FALSE);
4765 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4766 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4767 "ptr ptr ptr ptr", FALSE);
4768 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4769 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4770 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4771 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4772 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4773 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4774 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4775 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4776 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4777 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4778 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4779 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4780 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4781 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4782 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4783 register_icall (mono_value_copy_internal, "mono_value_copy_internal", "void ptr ptr ptr", FALSE);
4784 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4785 register_icall (mono_break, "mono_break", NULL, TRUE);
4786 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4787 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4788 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4789 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4790 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4791 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4792 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4793 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4794 register_icall (mono_resume_unwind, "mono_resume_unwind", "void ptr", TRUE);
4795 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4796 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4798 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4799 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4801 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4802 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4803 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4804 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4805 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4807 register_icall (mini_get_dbg_callbacks ()->user_break, "mono_debugger_agent_user_break", "void", FALSE);
4809 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4810 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4811 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4812 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4814 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4815 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4816 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4817 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4818 /* This needs a wrapper so it can have a preserveall cconv */
4819 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4820 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4821 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4822 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4823 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4824 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4825 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4827 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "int32 obj");
4828 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4829 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4830 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4832 #ifdef TARGET_IOS
4833 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4834 #endif
4835 /* Register tls icalls */
4836 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4837 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4838 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4839 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4840 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4841 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4842 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4843 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4844 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4845 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4847 register_icall_no_wrapper (mono_interp_entry_from_trampoline, "mono_interp_entry_from_trampoline", "void ptr ptr");
4849 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4850 mono_arch_register_icall ();
4851 #endif
4854 MonoJitStats mono_jit_stats = {0};
4857 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4858 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4860 MONO_NO_SANITIZE_THREAD
4861 static void
4862 print_jit_stats (void)
4864 if (mono_jit_stats.enabled) {
4865 g_print ("Mono Jit statistics\n");
4866 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4867 mono_jit_stats.max_ratio_method);
4868 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4869 mono_jit_stats.biggest_method);
4871 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4872 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4873 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4874 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4875 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4876 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4877 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4878 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4880 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4881 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4882 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4884 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4885 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4886 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4887 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4889 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4890 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4891 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4892 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4893 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4894 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4895 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4896 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4898 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4899 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4900 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4902 g_free (mono_jit_stats.max_ratio_method);
4903 mono_jit_stats.max_ratio_method = NULL;
4904 g_free (mono_jit_stats.biggest_method);
4905 mono_jit_stats.biggest_method = NULL;
4909 void
4910 mini_cleanup (MonoDomain *domain)
4912 if (mono_profiler_sampling_enabled ())
4913 mono_runtime_shutdown_stat_profiler ();
4915 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4917 #ifndef DISABLE_COM
4918 mono_cominterop_release_all_rcws ();
4919 #endif
4921 #ifndef MONO_CROSS_COMPILE
4923 * mono_domain_finalize () needs to be called early since it needs the
4924 * execution engine still fully working (it may invoke managed finalizers).
4926 mono_domain_finalize (domain, 2000);
4927 #endif
4929 /* This accesses metadata so needs to be called before runtime shutdown */
4930 print_jit_stats ();
4932 #ifndef MONO_CROSS_COMPILE
4933 mono_runtime_cleanup (domain);
4934 #endif
4936 mono_threadpool_cleanup ();
4938 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4940 mono_profiler_cleanup ();
4942 if (profile_options)
4943 g_ptr_array_free (profile_options, TRUE);
4945 free_jit_tls_data (mono_tls_get_jit_tls ());
4947 mono_icall_cleanup ();
4949 mono_runtime_cleanup_handlers ();
4951 #ifndef MONO_CROSS_COMPILE
4952 mono_domain_free (domain, TRUE);
4953 #endif
4955 #ifdef ENABLE_LLVM
4956 if (mono_use_llvm)
4957 mono_llvm_cleanup ();
4958 #endif
4960 mono_aot_cleanup ();
4962 mono_trampolines_cleanup ();
4964 mono_unwind_cleanup ();
4966 mono_code_manager_destroy (global_codeman);
4967 g_free (vtable_trampolines);
4969 mini_jit_cleanup ();
4971 mono_tramp_info_cleanup ();
4973 mono_arch_cleanup ();
4975 mono_generic_sharing_cleanup ();
4977 mono_cleanup ();
4979 mono_trace_cleanup ();
4981 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4983 if (mono_inject_async_exc_method)
4984 mono_method_desc_free (mono_inject_async_exc_method);
4986 mono_tls_free_keys ();
4988 mono_os_mutex_destroy (&jit_mutex);
4990 mono_code_manager_cleanup ();
4992 #ifndef HOST_WIN32
4993 mono_w32handle_cleanup ();
4994 #endif
4997 void
4998 mono_set_defaults (int verbose_level, guint32 opts)
5000 mini_verbose = verbose_level;
5001 mono_set_optimizations (opts);
5004 void
5005 mono_disable_optimizations (guint32 opts)
5007 default_opt &= ~opts;
5010 void
5011 mono_set_optimizations (guint32 opts)
5013 default_opt = opts;
5014 default_opt_set = TRUE;
5015 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
5016 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
5017 #else
5018 if (mono_llvm_only)
5019 mono_set_generic_sharing_vt_supported (TRUE);
5020 #endif
5023 void
5024 mono_set_verbose_level (guint32 level)
5026 mini_verbose = level;
5030 * mono_get_runtime_build_info:
5031 * The returned string is owned by the caller. The returned string
5032 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
5033 * \returns the runtime version + build date in string format.
5035 char*
5036 mono_get_runtime_build_info (void)
5038 if (mono_build_date)
5039 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
5040 else
5041 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
5044 static void
5045 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
5047 GHashTable *assemblies = (GHashTable*)user_data;
5048 MonoImage *image = mono_assembly_get_image_internal (ass);
5049 MonoMethod *method, *invoke;
5050 int i, count = 0;
5052 if (g_hash_table_lookup (assemblies, ass))
5053 return;
5055 g_hash_table_insert (assemblies, ass, ass);
5057 if (mini_verbose > 0)
5058 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
5060 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5061 ERROR_DECL (error);
5063 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
5064 if (!method) {
5065 mono_error_cleanup (error); /* FIXME don't swallow the error */
5066 continue;
5068 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
5069 continue;
5070 if (method->is_generic || mono_class_is_gtd (method->klass))
5071 continue;
5073 count++;
5074 if (mini_verbose > 1) {
5075 char * desc = mono_method_full_name (method, TRUE);
5076 g_print ("Compiling %d %s\n", count, desc);
5077 g_free (desc);
5079 mono_compile_method_checked (method, error);
5080 if (!is_ok (error)) {
5081 mono_error_cleanup (error); /* FIXME don't swallow the error */
5082 continue;
5084 if (strcmp (method->name, "Finalize") == 0) {
5085 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
5086 mono_compile_method_checked (invoke, error);
5087 mono_error_assert_ok (error);
5089 #ifndef DISABLE_REMOTING
5090 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
5091 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
5092 mono_error_assert_ok (error);
5093 mono_compile_method_checked (invoke, error);
5094 mono_error_assert_ok (error);
5096 #endif
5099 /* Load and precompile referenced assemblies as well */
5100 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
5101 mono_assembly_load_reference (image, i);
5102 if (image->references [i])
5103 mono_precompile_assembly (image->references [i], assemblies);
5107 void mono_precompile_assemblies ()
5109 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
5111 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
5113 g_hash_table_destroy (assemblies);
5117 * Used by LLVM.
5118 * Have to export this for AOT.
5120 void
5121 mono_personality (void)
5123 /* Not used */
5124 g_assert_not_reached ();
5128 static MonoBreakPolicy
5129 always_insert_breakpoint (MonoMethod *method)
5131 return MONO_BREAK_POLICY_ALWAYS;
5134 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5137 * mono_set_break_policy:
5138 * \param policy_callback the new callback function
5140 * Allow embedders to decide whether to actually obey breakpoint instructions
5141 * (both break IL instructions and \c Debugger.Break method calls), for example
5142 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5143 * untrusted or semi-trusted code.
5145 * \p policy_callback will be called every time a break point instruction needs to
5146 * be inserted with the method argument being the method that calls \c Debugger.Break
5147 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5148 * if it wants the breakpoint to not be effective in the given method.
5149 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5151 void
5152 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5154 if (policy_callback)
5155 break_policy_func = policy_callback;
5156 else
5157 break_policy_func = always_insert_breakpoint;
5160 gboolean
5161 mini_should_insert_breakpoint (MonoMethod *method)
5163 switch (break_policy_func (method)) {
5164 case MONO_BREAK_POLICY_ALWAYS:
5165 return TRUE;
5166 case MONO_BREAK_POLICY_NEVER:
5167 return FALSE;
5168 case MONO_BREAK_POLICY_ON_DBG:
5169 g_warning ("mdb no longer supported");
5170 return FALSE;
5171 default:
5172 g_warning ("Incorrect value returned from break policy callback");
5173 return FALSE;
5177 // Custom handlers currently only implemented by Windows.
5178 #ifndef HOST_WIN32
5179 gboolean
5180 mono_runtime_install_custom_handlers (const char *handlers)
5182 return FALSE;
5185 void
5186 mono_runtime_install_custom_handlers_usage (void)
5188 fprintf (stdout,
5189 "Custom Handlers:\n"
5190 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5191 " separated list of available handlers to install.\n"
5192 "\n"
5193 "No handlers supported on current platform.\n");
5195 #endif /* HOST_WIN32 */