[interp] Small fixes (#11667)
[mono-project.git] / mono / mini / mini-runtime.c
blob99d430c4e69e353e21d731ef3c8275e387b4a920
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_INTERNAL_METHOD: {
1110 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1111 break;
1113 default:
1114 printf ("[%s]", patch_info_str [ji->type]);
1115 break;
1119 #else
1121 const char*
1122 mono_ji_type_to_string (MonoJumpInfoType type)
1124 return "";
1127 void
1128 mono_print_ji (const MonoJumpInfo *ji)
1132 #endif
1135 * mono_patch_info_dup_mp:
1137 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1139 MonoJumpInfo*
1140 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1142 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1143 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1145 switch (patch_info->type) {
1146 case MONO_PATCH_INFO_RVA:
1147 case MONO_PATCH_INFO_LDSTR:
1148 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1149 case MONO_PATCH_INFO_LDTOKEN:
1150 case MONO_PATCH_INFO_DECLSEC:
1151 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1152 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1153 break;
1154 case MONO_PATCH_INFO_SWITCH:
1155 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1156 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1157 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1158 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1159 break;
1160 case MONO_PATCH_INFO_RGCTX_FETCH:
1161 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1162 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1163 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1164 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1165 break;
1166 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1167 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1168 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1169 break;
1170 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1171 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1172 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1173 break;
1174 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1175 MonoGSharedVtMethodInfo *info;
1176 MonoGSharedVtMethodInfo *oinfo;
1177 int i;
1179 oinfo = patch_info->data.gsharedvt_method;
1180 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1181 res->data.gsharedvt_method = info;
1182 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1183 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1184 for (i = 0; i < oinfo->num_entries; ++i) {
1185 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1186 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1188 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1190 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1191 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1192 break;
1194 case MONO_PATCH_INFO_VIRT_METHOD: {
1195 MonoJumpInfoVirtMethod *info;
1196 MonoJumpInfoVirtMethod *oinfo;
1198 oinfo = patch_info->data.virt_method;
1199 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1200 res->data.virt_method = info;
1201 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1202 break;
1204 default:
1205 break;
1208 return res;
1211 guint
1212 mono_patch_info_hash (gconstpointer data)
1214 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1216 switch (ji->type) {
1217 case MONO_PATCH_INFO_RVA:
1218 case MONO_PATCH_INFO_LDSTR:
1219 case MONO_PATCH_INFO_LDTOKEN:
1220 case MONO_PATCH_INFO_DECLSEC:
1221 return (ji->type << 8) | ji->data.token->token;
1222 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1223 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1224 case MONO_PATCH_INFO_INTERNAL_METHOD:
1225 return (ji->type << 8) | g_str_hash (ji->data.name);
1226 case MONO_PATCH_INFO_VTABLE:
1227 case MONO_PATCH_INFO_CLASS:
1228 case MONO_PATCH_INFO_IID:
1229 case MONO_PATCH_INFO_ADJUSTED_IID:
1230 case MONO_PATCH_INFO_METHODCONST:
1231 case MONO_PATCH_INFO_METHOD:
1232 case MONO_PATCH_INFO_METHOD_JUMP:
1233 case MONO_PATCH_INFO_IMAGE:
1234 case MONO_PATCH_INFO_ICALL_ADDR:
1235 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1236 case MONO_PATCH_INFO_FIELD:
1237 case MONO_PATCH_INFO_SFLDA:
1238 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1239 case MONO_PATCH_INFO_METHOD_RGCTX:
1240 case MONO_PATCH_INFO_SIGNATURE:
1241 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1242 case MONO_PATCH_INFO_AOT_JIT_INFO:
1243 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1244 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1245 return (ji->type << 8) | (gssize)ji->data.target;
1246 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1247 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1248 case MONO_PATCH_INFO_RGCTX_FETCH:
1249 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1250 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1252 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1254 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1255 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1256 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1257 case MONO_PATCH_INFO_GC_NURSERY_START:
1258 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1259 case MONO_PATCH_INFO_GOT_OFFSET:
1260 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1261 case MONO_PATCH_INFO_AOT_MODULE:
1262 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1263 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1264 return (ji->type << 8);
1265 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1266 return (ji->type << 8) | (ji->data.index);
1267 case MONO_PATCH_INFO_SWITCH:
1268 return (ji->type << 8) | ji->data.table->table_size;
1269 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1270 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1271 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1272 /* Hash on the selector name */
1273 return g_str_hash (ji->data.target);
1274 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1275 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1276 case MONO_PATCH_INFO_LDSTR_LIT:
1277 return g_str_hash (ji->data.target);
1278 case MONO_PATCH_INFO_VIRT_METHOD: {
1279 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1281 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1283 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1284 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1285 return (ji->type << 8) | g_str_hash (ji->data.target);
1286 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1287 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1288 default:
1289 printf ("info type: %d\n", ji->type);
1290 mono_print_ji (ji); printf ("\n");
1291 g_assert_not_reached ();
1292 return 0;
1297 * mono_patch_info_equal:
1299 * This might fail to recognize equivalent patches, i.e. floats, so its only
1300 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1301 * in AOT.
1303 gint
1304 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1306 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1307 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1309 if (ji1->type != ji2->type)
1310 return 0;
1312 switch (ji1->type) {
1313 case MONO_PATCH_INFO_RVA:
1314 case MONO_PATCH_INFO_LDSTR:
1315 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1316 case MONO_PATCH_INFO_LDTOKEN:
1317 case MONO_PATCH_INFO_DECLSEC:
1318 if ((ji1->data.token->image != ji2->data.token->image) ||
1319 (ji1->data.token->token != ji2->data.token->token) ||
1320 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1321 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1322 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1323 return 0;
1324 break;
1325 case MONO_PATCH_INFO_INTERNAL_METHOD:
1326 return g_str_equal (ji1->data.name, ji2->data.name);
1327 case MONO_PATCH_INFO_RGCTX_FETCH:
1328 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1329 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1330 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1332 return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
1334 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1335 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1336 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1338 return c1->sig == c2->sig && c1->method == c2->method;
1340 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1341 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1342 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1343 return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->is_virtual == ji2->data.del_tramp->is_virtual;
1344 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1345 return ji1->data.index == ji2->data.index;
1346 case MONO_PATCH_INFO_VIRT_METHOD:
1347 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1348 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1349 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1350 if (ji1->data.target == ji2->data.target)
1351 return 1;
1352 return strcmp ((const char*)ji1->data.target, (const char*)ji2->data.target) == 0 ? 1 : 0;
1353 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1354 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1355 default:
1356 if (ji1->data.target != ji2->data.target)
1357 return 0;
1358 break;
1361 return 1;
1364 gpointer
1365 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1367 unsigned char *ip = patch_info->ip.i + code;
1368 gconstpointer target = NULL;
1370 error_init (error);
1372 switch (patch_info->type) {
1373 case MONO_PATCH_INFO_BB:
1375 * FIXME: This could be hit for methods without a prolog. Should use -1
1376 * but too much code depends on a 0 initial value.
1378 //g_assert (patch_info->data.bb->native_offset);
1379 target = patch_info->data.bb->native_offset + code;
1380 break;
1381 case MONO_PATCH_INFO_ABS:
1382 target = patch_info->data.target;
1383 break;
1384 case MONO_PATCH_INFO_LABEL:
1385 target = patch_info->data.inst->inst_c0 + code;
1386 break;
1387 case MONO_PATCH_INFO_IP:
1388 target = ip;
1389 break;
1390 case MONO_PATCH_INFO_METHOD_REL:
1391 target = code + patch_info->data.offset;
1392 break;
1393 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1394 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1395 if (!mi) {
1396 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1397 g_assert_not_reached ();
1399 target = mono_icall_get_wrapper (mi);
1400 break;
1402 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1403 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1404 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1405 if (!mi) {
1406 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1407 g_assert_not_reached ();
1409 target = mi->func;
1410 break;
1412 case MONO_PATCH_INFO_METHOD_JUMP:
1413 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1414 if (!mono_error_ok (error))
1415 return NULL;
1416 break;
1417 case MONO_PATCH_INFO_METHOD:
1418 if (patch_info->data.method == method) {
1419 target = code;
1420 } else {
1421 /* get the trampoline to the method from the domain */
1422 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1423 if (!mono_error_ok (error))
1424 return NULL;
1426 break;
1427 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1428 gpointer code_slot;
1430 mono_domain_lock (domain);
1431 if (!domain_jit_info (domain)->method_code_hash)
1432 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1433 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1434 if (!code_slot) {
1435 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1436 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1438 mono_domain_unlock (domain);
1439 target = code_slot;
1440 break;
1442 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1443 target = (gpointer)&mono_polling_required;
1444 break;
1445 case MONO_PATCH_INFO_SWITCH: {
1446 gpointer *jump_table;
1447 int i;
1448 if (method && method->dynamic) {
1449 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1450 } else {
1451 if (mono_aot_only) {
1452 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1453 } else {
1454 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1458 for (i = 0; i < patch_info->data.table->table_size; i++) {
1459 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1462 target = jump_table;
1463 break;
1465 case MONO_PATCH_INFO_METHODCONST:
1466 case MONO_PATCH_INFO_CLASS:
1467 case MONO_PATCH_INFO_IMAGE:
1468 case MONO_PATCH_INFO_FIELD:
1469 case MONO_PATCH_INFO_SIGNATURE:
1470 case MONO_PATCH_INFO_AOT_MODULE:
1471 target = patch_info->data.target;
1472 break;
1473 case MONO_PATCH_INFO_IID:
1474 mono_class_init (patch_info->data.klass);
1475 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1476 break;
1477 case MONO_PATCH_INFO_ADJUSTED_IID:
1478 mono_class_init (patch_info->data.klass);
1479 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1480 break;
1481 case MONO_PATCH_INFO_VTABLE:
1482 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1483 mono_error_assert_ok (error);
1484 break;
1485 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1486 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1488 if (del_tramp->is_virtual)
1489 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1490 else
1491 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1492 break;
1494 case MONO_PATCH_INFO_SFLDA: {
1495 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1496 mono_error_assert_ok (error);
1498 if (mono_class_field_is_special_static (patch_info->data.field)) {
1499 gpointer addr = NULL;
1501 mono_domain_lock (domain);
1502 if (domain->special_static_fields)
1503 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1504 mono_domain_unlock (domain);
1505 g_assert (addr);
1506 return addr;
1509 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1510 /* Done by the generated code */
1512 else {
1513 if (run_cctors) {
1514 if (!mono_runtime_class_init_full (vtable, error)) {
1515 return NULL;
1519 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1520 break;
1522 case MONO_PATCH_INFO_RVA: {
1523 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1524 guint32 rva;
1526 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1527 target = mono_image_rva_map (patch_info->data.token->image, rva);
1528 break;
1530 case MONO_PATCH_INFO_R4:
1531 case MONO_PATCH_INFO_R8:
1532 target = patch_info->data.target;
1533 break;
1534 case MONO_PATCH_INFO_EXC_NAME:
1535 target = patch_info->data.name;
1536 break;
1537 case MONO_PATCH_INFO_LDSTR:
1538 target =
1539 mono_ldstr_checked (domain, patch_info->data.token->image,
1540 mono_metadata_token_index (patch_info->data.token->token), error);
1541 break;
1542 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1543 gpointer handle;
1544 MonoClass *handle_class;
1546 handle = mono_ldtoken_checked (patch_info->data.token->image,
1547 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1548 if (!mono_error_ok (error))
1549 return NULL;
1550 mono_class_init (handle_class);
1551 mono_class_init (mono_class_from_mono_type_internal ((MonoType *)handle));
1553 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1554 if (!mono_error_ok (error))
1555 return NULL;
1556 break;
1558 case MONO_PATCH_INFO_LDTOKEN: {
1559 gpointer handle;
1560 MonoClass *handle_class;
1562 handle = mono_ldtoken_checked (patch_info->data.token->image,
1563 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1564 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1565 mono_class_init (handle_class);
1567 target = handle;
1568 break;
1570 case MONO_PATCH_INFO_DECLSEC:
1571 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1572 break;
1573 case MONO_PATCH_INFO_ICALL_ADDR:
1574 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1575 /* run_cctors == 0 -> AOT */
1576 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1577 const char *exc_class;
1578 const char *exc_arg;
1580 if (run_cctors) {
1581 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1582 if (!target) {
1583 if (mono_aot_only) {
1584 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1585 return NULL;
1587 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));
1589 } else {
1590 target = NULL;
1592 } else {
1593 target = mono_lookup_internal_call (patch_info->data.method);
1595 if (!target && run_cctors)
1596 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1598 break;
1599 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1600 target = mono_thread_interruption_request_flag ();
1601 break;
1602 case MONO_PATCH_INFO_METHOD_RGCTX:
1603 target = mini_method_get_rgctx (patch_info->data.method);
1604 break;
1605 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1606 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1608 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1609 break;
1611 case MONO_PATCH_INFO_BB_OVF:
1612 case MONO_PATCH_INFO_EXC_OVF:
1613 case MONO_PATCH_INFO_GOT_OFFSET:
1614 case MONO_PATCH_INFO_NONE:
1615 break;
1616 case MONO_PATCH_INFO_RGCTX_FETCH: {
1617 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1619 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1620 break;
1622 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1623 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1624 if (!run_cctors)
1625 /* AOT, not needed */
1626 target = NULL;
1627 else
1628 target = mono_arch_get_seq_point_info (domain, code);
1629 break;
1630 #endif
1631 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1632 int card_table_shift_bits;
1633 gpointer card_table_mask;
1635 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1636 break;
1638 case MONO_PATCH_INFO_GC_NURSERY_START: {
1639 int shift_bits;
1640 size_t size;
1642 target = mono_gc_get_nursery (&shift_bits, &size);
1643 break;
1645 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1646 int shift_bits;
1647 size_t size;
1649 mono_gc_get_nursery (&shift_bits, &size);
1651 target = (gpointer)(gssize)shift_bits;
1652 break;
1654 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1655 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1656 break;
1658 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1659 target = NULL;
1660 break;
1662 case MONO_PATCH_INFO_LDSTR_LIT: {
1663 int len;
1664 char *s;
1666 len = strlen ((const char *)patch_info->data.target);
1667 s = (char *)mono_domain_alloc0 (domain, len + 1);
1668 memcpy (s, patch_info->data.target, len);
1669 target = s;
1671 break;
1673 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1674 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1675 break;
1676 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1677 target = mono_tls_get_tls_getter ((MonoTlsKey)patch_info->data.index, FALSE);
1678 break;
1679 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1680 target = mono_tls_get_tls_setter ((MonoTlsKey)patch_info->data.index, FALSE);
1681 break;
1682 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1683 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1684 break;
1686 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1687 target = (gpointer) &mono_profiler_state.exception_clause_count;
1688 break;
1690 default:
1691 g_assert_not_reached ();
1694 return (gpointer)target;
1698 * mini_register_jump_site:
1700 * Register IP as a jump/tailcall site which calls METHOD.
1701 * This is needed because common_call_trampoline () cannot patch
1702 * the call site because the caller ip is not available for jumps.
1704 void
1705 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1707 MonoJumpList *jlist;
1709 MonoMethod *shared_method = mini_method_to_shared (method);
1710 method = shared_method ? shared_method : method;
1712 mono_domain_lock (domain);
1713 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1714 if (!jlist) {
1715 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1716 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1718 jlist->list = g_slist_prepend (jlist->list, ip);
1719 mono_domain_unlock (domain);
1723 * mini_patch_jump_sites:
1725 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1727 void
1728 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1730 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1732 if (!hash)
1733 return;
1735 MonoJumpInfo patch_info;
1736 MonoJumpList *jlist;
1737 GSList *tmp;
1739 /* The caller/callee might use different instantiations */
1740 MonoMethod *shared_method = mini_method_to_shared (method);
1741 method = shared_method ? shared_method : method;
1743 mono_domain_lock (domain);
1744 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1745 if (jlist)
1746 g_hash_table_remove (hash, method);
1747 mono_domain_unlock (domain);
1748 if (jlist) {
1749 patch_info.next = NULL;
1750 patch_info.ip.i = 0;
1751 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1752 patch_info.data.method = method;
1754 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1755 for (tmp = jlist->list; tmp; tmp = tmp->next)
1756 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1757 #else
1758 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1759 // for gshared methods
1760 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1761 ERROR_DECL (error);
1762 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1763 mono_error_assert_ok (error);
1765 #endif
1769 void
1770 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1772 MonoGenericInst *inst;
1773 int i;
1775 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1777 if (context && context->class_inst) {
1778 inst = context->class_inst;
1779 for (i = 0; i < inst->type_argc; ++i) {
1780 MonoType *type = inst->type_argv [i];
1782 if (mini_is_gsharedvt_gparam (type))
1783 gsctx->is_gsharedvt = TRUE;
1786 if (context && context->method_inst) {
1787 inst = context->method_inst;
1789 for (i = 0; i < inst->type_argc; ++i) {
1790 MonoType *type = inst->type_argv [i];
1792 if (mini_is_gsharedvt_gparam (type))
1793 gsctx->is_gsharedvt = TRUE;
1799 * LOCKING: Acquires the jit code hash lock.
1801 MonoJitInfo*
1802 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1804 MonoJitInfo *ji;
1805 static gboolean inited = FALSE;
1806 static int lookups = 0;
1807 static int failed_lookups = 0;
1809 mono_domain_jit_code_hash_lock (domain);
1810 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1811 if (!ji && shared) {
1812 /* Try generic sharing */
1813 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1814 if (ji && !ji->has_generic_jit_info)
1815 ji = NULL;
1816 if (!inited) {
1817 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1818 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1819 inited = TRUE;
1822 ++lookups;
1823 if (!ji)
1824 ++failed_lookups;
1826 mono_domain_jit_code_hash_unlock (domain);
1828 return ji;
1831 static MonoJitInfo*
1832 lookup_method (MonoDomain *domain, MonoMethod *method)
1834 ERROR_DECL (error);
1835 MonoJitInfo *ji;
1836 MonoMethod *shared;
1838 ji = mini_lookup_method (domain, method, NULL);
1840 if (!ji) {
1841 if (!mono_method_is_generic_sharable (method, FALSE))
1842 return NULL;
1843 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1844 mono_error_assert_ok (error);
1845 ji = mini_lookup_method (domain, method, shared);
1848 return ji;
1851 MonoClass*
1852 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1854 ERROR_DECL (error);
1855 MonoClass *klass;
1857 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1858 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1859 if (context) {
1860 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1861 mono_error_cleanup (error); /* FIXME don't swallow the error */
1863 } else {
1864 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1865 mono_error_cleanup (error); /* FIXME don't swallow the error */
1867 if (klass)
1868 mono_class_init (klass);
1869 return klass;
1872 #if ENABLE_JIT_MAP
1873 static FILE* perf_map_file;
1875 void
1876 mono_enable_jit_map (void)
1878 if (!perf_map_file) {
1879 char name [64];
1880 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1881 unlink (name);
1882 perf_map_file = fopen (name, "w");
1886 void
1887 mono_emit_jit_tramp (void *start, int size, const char *desc)
1889 if (perf_map_file)
1890 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1893 void
1894 mono_emit_jit_map (MonoJitInfo *jinfo)
1896 if (perf_map_file) {
1897 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1898 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1899 g_free (name);
1903 gboolean
1904 mono_jit_map_is_enabled (void)
1906 return perf_map_file != NULL;
1909 #endif
1911 static void
1912 no_gsharedvt_in_wrapper (void)
1914 g_assert_not_reached ();
1918 Overall algorithm:
1920 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.
1921 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1922 Dependency management in this case is too complex to justify implementing it.
1924 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1926 TODO:
1927 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1928 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1929 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1930 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1932 typedef struct {
1933 MonoMethod *method;
1934 MonoDomain *domain;
1935 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1936 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1937 int threads_waiting; /* Number of threads waiting on this job */
1938 gboolean has_cond; /* True if @cond was initialized */
1939 gboolean done; /* True if the method finished JIT'ing */
1940 MonoCoopCond cond; /* Cond sleeping threads wait one */
1941 } JitCompilationEntry;
1943 typedef struct {
1944 GPtrArray *in_flight_methods; //JitCompilationEntry*
1945 MonoCoopMutex lock;
1946 } JitCompilationData;
1949 Timeout, in millisecounds, that we wait other threads to finish JITing.
1950 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.
1952 #define MAX_JIT_TIMEOUT_MS 1000
1955 static JitCompilationData compilation_data;
1956 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
1958 static void
1959 mini_jit_init_job_control (void)
1961 mono_coop_mutex_init (&compilation_data.lock);
1962 compilation_data.in_flight_methods = g_ptr_array_new ();
1965 static void
1966 lock_compilation_data (void)
1968 mono_coop_mutex_lock (&compilation_data.lock);
1971 static void
1972 unlock_compilation_data (void)
1974 mono_coop_mutex_unlock (&compilation_data.lock);
1977 static JitCompilationEntry*
1978 find_method (MonoMethod *method, MonoDomain *domain)
1980 int i;
1981 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1982 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
1983 if (e->method == method && e->domain == domain)
1984 return e;
1987 return NULL;
1990 static void
1991 add_current_thread (MonoJitTlsData *jit_tls)
1993 ++jit_tls->active_jit_methods;
1996 static void
1997 unref_jit_entry (JitCompilationEntry *entry)
1999 --entry->ref_count;
2000 if (entry->ref_count)
2001 return;
2002 if (entry->has_cond)
2003 mono_coop_cond_destroy (&entry->cond);
2004 g_free (entry);
2008 * Returns true if this method waited successfully for another thread to JIT it
2010 static gboolean
2011 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2013 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2014 JitCompilationEntry *entry;
2016 static gboolean inited;
2017 if (!inited) {
2018 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2019 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2020 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2021 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2022 inited = TRUE;
2025 lock_compilation_data ();
2027 if (!(entry = find_method (method, domain))) {
2028 entry = g_new0 (JitCompilationEntry, 1);
2029 entry->method = method;
2030 entry->domain = domain;
2031 entry->compilation_count = entry->ref_count = 1;
2032 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2033 g_assert (find_method (method, domain) == entry);
2034 add_current_thread (jit_tls);
2036 unlock_compilation_data ();
2037 return FALSE;
2038 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2039 //We can't suspend the current thread if it's already JITing a method.
2040 //Dependency management is too compilated and we want to get rid of this anyways.
2042 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2043 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2045 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2046 ++entry->compilation_count;
2047 ++jit_methods_multiple;
2048 ++jit_tls->active_jit_methods;
2050 unlock_compilation_data ();
2051 return FALSE;
2052 } else {
2053 ++jit_methods_waited;
2054 ++entry->ref_count;
2056 if (!entry->has_cond) {
2057 mono_coop_cond_init (&entry->cond);
2058 entry->has_cond = TRUE;
2061 while (TRUE) {
2062 ++entry->threads_waiting;
2064 g_assert (entry->has_cond);
2065 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2066 --entry->threads_waiting;
2068 if (entry->done) {
2069 unref_jit_entry (entry);
2070 unlock_compilation_data ();
2071 return TRUE;
2072 } else {
2073 //We hit the timeout or a spurious wakeup, fallback to JITing
2074 g_assert (entry->ref_count > 1);
2075 unref_jit_entry (entry);
2076 ++jit_spurious_wakeups_or_timeouts;
2078 ++entry->compilation_count;
2079 ++jit_methods_multiple;
2080 ++jit_tls->active_jit_methods;
2082 unlock_compilation_data ();
2083 return FALSE;
2089 static void
2090 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2092 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2094 lock_compilation_data ();
2096 g_assert (jit_tls->active_jit_methods > 0);
2097 --jit_tls->active_jit_methods;
2099 JitCompilationEntry *entry = find_method (method, target_domain);
2100 g_assert (entry); // It would be weird to fail
2101 entry->done = TRUE;
2103 if (entry->threads_waiting) {
2104 g_assert (entry->has_cond);
2105 mono_coop_cond_broadcast (&entry->cond);
2108 if (--entry->compilation_count == 0) {
2109 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2110 unref_jit_entry (entry);
2113 unlock_compilation_data ();
2116 static MonoJitInfo*
2117 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2119 MonoDomain *domain = mono_get_root_domain ();
2120 MonoJitInfo *jinfo;
2121 guint8 *uw_info;
2122 guint32 info_len;
2124 if (info->uw_info) {
2125 uw_info = info->uw_info;
2126 info_len = info->uw_info_len;
2127 } else {
2128 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2131 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2132 jinfo->d.method = wrapper;
2133 jinfo->code_start = info->code;
2134 jinfo->code_size = info->code_size;
2135 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2137 if (!info->uw_info)
2138 g_free (uw_info);
2140 return jinfo;
2143 static gpointer
2144 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2146 MonoJitInfo *jinfo;
2147 gpointer code;
2149 if (mono_llvm_only) {
2150 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2151 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2153 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2155 * These wrappers are only created for signatures which are in the program, but
2156 * sometimes we load methods too eagerly and have to create them even if they
2157 * will never be called.
2159 return (gpointer)no_gsharedvt_in_wrapper;
2164 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2165 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2166 MonoMethod *nm;
2167 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2169 if (!piinfo->addr) {
2170 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2171 piinfo->addr = mono_lookup_internal_call (method);
2172 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2173 #ifdef HOST_WIN32
2174 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);
2175 #else
2176 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);
2177 #endif
2178 else
2179 mono_lookup_pinvoke_call (method, NULL, NULL);
2181 nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2182 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2183 return_val_if_nok (error, NULL);
2184 code = mono_get_addr_from_ftnptr (compiled_method);
2185 jinfo = mono_jit_info_table_find (target_domain, code);
2186 if (!jinfo)
2187 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2188 if (jinfo)
2189 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2190 return code;
2191 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2192 const char *name = method->name;
2193 char *full_name;
2194 MonoMethod *nm;
2196 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2197 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2198 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2199 g_assert (mi);
2201 * We need to make sure this wrapper
2202 * is compiled because it might end up
2203 * in an (M)RGCTX if generic sharing
2204 * is enabled, and would be called
2205 * indirectly. If it were a
2206 * trampoline we'd try to patch that
2207 * indirect call, which is not
2208 * possible.
2210 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2211 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2212 if (mono_llvm_only) {
2213 nm = mono_marshal_get_delegate_invoke (method, NULL);
2214 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2215 return_val_if_nok (error, NULL);
2216 return mono_get_addr_from_ftnptr (compiled_ptr);
2219 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2220 if (mono_use_interpreter)
2221 return NULL;
2223 return mono_create_delegate_trampoline (target_domain, method->klass);
2224 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2225 nm = mono_marshal_get_delegate_begin_invoke (method);
2226 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2227 return_val_if_nok (error, NULL);
2228 return mono_get_addr_from_ftnptr (compiled_ptr);
2229 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2230 nm = mono_marshal_get_delegate_end_invoke (method);
2231 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2232 return_val_if_nok (error, NULL);
2233 return mono_get_addr_from_ftnptr (compiled_ptr);
2237 full_name = mono_method_full_name (method, TRUE);
2238 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2239 g_free (full_name);
2240 return NULL;
2243 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2244 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2246 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2247 static MonoTrampInfo *in_tinfo, *out_tinfo;
2248 MonoTrampInfo *tinfo;
2249 MonoJitInfo *jinfo;
2250 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2252 if (is_in && in_tinfo)
2253 return in_tinfo->code;
2254 else if (!is_in && out_tinfo)
2255 return out_tinfo->code;
2258 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2259 * works.
2260 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2262 if (mono_ee_features.use_aot_trampolines)
2263 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2264 else
2265 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2266 jinfo = create_jit_info_for_trampoline (method, tinfo);
2267 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2268 if (is_in)
2269 in_tinfo = tinfo;
2270 else
2271 out_tinfo = tinfo;
2272 return tinfo->code;
2276 return NULL;
2279 static gpointer
2280 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2282 MonoDomain *target_domain, *domain = mono_domain_get ();
2283 MonoJitInfo *info;
2284 gpointer code = NULL, p;
2285 MonoJitInfo *ji;
2286 MonoJitICallInfo *callinfo = NULL;
2287 WrapperInfo *winfo = NULL;
2288 gboolean use_interp = FALSE;
2290 error_init (error);
2292 if (mono_ee_features.force_use_interpreter && !jit_only)
2293 use_interp = TRUE;
2294 if (!use_interp && mono_interp_only_classes) {
2295 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2296 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2297 use_interp = TRUE;
2300 if (use_interp) {
2301 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2302 if (code)
2303 return code;
2306 if (mono_llvm_only)
2307 /* Should be handled by the caller */
2308 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2311 * ICALL wrappers are handled specially, since there is only one copy of them
2312 * shared by all appdomains.
2314 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2315 winfo = mono_marshal_get_wrapper_info (method);
2316 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2317 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2318 g_assert (callinfo);
2320 /* Must be domain neutral since there is only one copy */
2321 opt |= MONO_OPT_SHARED;
2322 } else {
2323 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2324 opt &= ~MONO_OPT_SHARED;
2327 if (opt & MONO_OPT_SHARED)
2328 target_domain = mono_get_root_domain ();
2329 else
2330 target_domain = domain;
2332 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2333 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2335 g_assert (info);
2336 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2337 MonoGenericContext *ctx = NULL;
2338 if (method->is_inflated)
2339 ctx = mono_method_get_context (method);
2340 method = info->d.synchronized_inner.method;
2341 if (ctx) {
2342 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2343 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2348 lookup_start:
2349 info = lookup_method (target_domain, method);
2350 if (info) {
2351 /* We can't use a domain specific method in another domain */
2352 if (! ((domain != target_domain) && !info->domain_neutral)) {
2353 MonoVTable *vtable;
2355 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2356 vtable = mono_class_vtable_checked (domain, method->klass, error);
2357 if (!is_ok (error))
2358 return NULL;
2359 g_assert (vtable);
2360 if (!mono_runtime_class_init_full (vtable, error))
2361 return NULL;
2362 return mono_create_ftnptr (target_domain, info->code_start);
2366 #ifdef MONO_USE_AOT_COMPILER
2367 if (opt & MONO_OPT_AOT) {
2368 MonoDomain *domain = NULL;
2370 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2371 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2372 g_assert (info);
2373 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2374 /* AOT'd wrappers for interp must be owned by root domain */
2375 domain = mono_get_root_domain ();
2378 if (!domain)
2379 domain = mono_domain_get ();
2381 mono_class_init (method->klass);
2383 if ((code = mono_aot_get_method (domain, method, error))) {
2384 MonoVTable *vtable;
2386 if (mono_gc_is_critical_method (method)) {
2388 * The suspend code needs to be able to lookup these methods by ip in async context,
2389 * so preload their jit info.
2391 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2392 g_assert (ji);
2396 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2397 * This is not a problem, since it will be initialized when the method is first
2398 * called by init_method ().
2400 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2401 vtable = mono_class_vtable_checked (domain, method->klass, error);
2402 mono_error_assert_ok (error);
2403 if (!mono_runtime_class_init_full (vtable, error))
2404 return NULL;
2407 if (!is_ok (error))
2408 return NULL;
2410 #endif
2412 if (!code)
2413 code = compile_special (method, target_domain, error);
2415 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_UNKNOWN)
2416 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2418 if (!code) {
2419 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2420 char *full_name = mono_type_get_full_name (method->klass);
2421 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2422 g_free (full_name);
2423 return NULL;
2426 if (mono_aot_only) {
2427 char *fullname = mono_method_get_full_name (method);
2428 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);
2429 g_free (fullname);
2431 return NULL;
2434 if (wait_or_register_method_to_compile (method, target_domain))
2435 goto lookup_start;
2436 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2437 unregister_method_for_compile (method, target_domain);
2439 if (!mono_error_ok (error))
2440 return NULL;
2442 if (!code && mono_llvm_only) {
2443 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2444 g_assert_not_reached ();
2447 if (!code)
2448 return NULL;
2450 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2451 #ifndef HOST_WASM
2452 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2453 MonoDomain *d;
2456 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2458 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2459 g_assert (ji);
2461 #endif
2463 p = mono_create_ftnptr (target_domain, code);
2465 if (callinfo) {
2466 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2467 mono_loader_lock ();
2468 mono_jit_lock ();
2469 if (!callinfo->wrapper) {
2470 callinfo->wrapper = p;
2471 mono_register_jit_icall_wrapper (callinfo, p);
2473 mono_jit_unlock ();
2474 mono_loader_unlock ();
2477 return p;
2480 gpointer
2481 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2483 gpointer code;
2485 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2486 return code;
2490 * mono_jit_compile_method_jit_only:
2492 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2494 gpointer
2495 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2497 gpointer code;
2499 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2500 return code;
2503 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2504 static void
2505 invalidated_delegate_trampoline (char *desc)
2507 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2508 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2509 desc);
2511 #endif
2514 * mono_jit_free_method:
2516 * Free all memory allocated by the JIT for METHOD.
2518 static void
2519 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2521 MonoJitDynamicMethodInfo *ji;
2522 gboolean destroy = TRUE, removed;
2523 GHashTableIter iter;
2524 MonoJumpList *jlist;
2525 MonoJitDomainInfo *info = domain_jit_info (domain);
2527 g_assert (method->dynamic);
2529 if (mono_use_interpreter) {
2530 mono_domain_jit_code_hash_lock (domain);
2531 /* InterpMethod is allocated in the domain mempool. We might haven't
2532 * allocated an InterpMethod for this instance yet */
2533 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2534 mono_domain_jit_code_hash_unlock (domain);
2537 mono_domain_lock (domain);
2538 ji = mono_dynamic_code_hash_lookup (domain, method);
2539 mono_domain_unlock (domain);
2541 if (!ji)
2542 return;
2544 mono_debug_remove_method (method, domain);
2545 mono_lldb_remove_method (domain, method, ji);
2547 mono_domain_lock (domain);
2548 g_hash_table_remove (info->dynamic_code_hash, method);
2549 mono_domain_jit_code_hash_lock (domain);
2550 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2551 g_assert (removed);
2552 mono_domain_jit_code_hash_unlock (domain);
2553 g_hash_table_remove (info->jump_trampoline_hash, method);
2554 g_hash_table_remove (info->seq_points, method);
2556 ji->ji->seq_points = NULL;
2558 /* requires the domain lock - took above */
2559 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2561 /* Remove jump targets in this method */
2562 g_hash_table_iter_init (&iter, info->jump_target_hash);
2563 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2564 GSList *tmp, *remove;
2566 remove = NULL;
2567 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2568 guint8 *ip = (guint8 *)tmp->data;
2570 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2571 remove = g_slist_prepend (remove, tmp);
2573 for (tmp = remove; tmp; tmp = tmp->next) {
2574 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2576 g_slist_free (remove);
2578 mono_domain_unlock (domain);
2580 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2581 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2583 * Instead of freeing the code, change it to call an error routine
2584 * so people can fix their code.
2586 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2587 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2589 g_free (type);
2590 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2591 destroy = FALSE;
2593 #endif
2596 * This needs to be done before freeing code_mp, since the code address is the
2597 * key in the table, so if we free the code_mp first, another thread can grab the
2598 * same code address and replace our entry in the table.
2600 mono_jit_info_table_remove (domain, ji->ji);
2602 if (destroy)
2603 mono_code_manager_destroy (ji->code_mp);
2604 g_free (ji);
2607 gpointer
2608 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2610 gpointer code;
2611 MonoJitInfo *ji;
2613 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2614 if (!code) {
2615 ERROR_DECL_VALUE (oerror);
2617 /* Might be AOTed code */
2618 mono_class_init (method->klass);
2619 code = mono_aot_get_method (domain, method, &oerror);
2620 if (code) {
2621 mono_error_assert_ok (&oerror);
2622 ji = mono_jit_info_table_find (domain, code);
2623 } else {
2624 if (!is_ok (&oerror))
2625 mono_error_cleanup (&oerror);
2627 /* Might be interpreted */
2628 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2632 *out_ji = ji;
2634 return code;
2637 gpointer
2638 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2640 MonoDomain *target_domain;
2641 MonoJitInfo *info;
2643 if (default_opt & MONO_OPT_SHARED)
2644 target_domain = mono_get_root_domain ();
2645 else
2646 target_domain = domain;
2648 info = lookup_method (target_domain, method);
2649 if (info) {
2650 /* We can't use a domain specific method in another domain */
2651 if (! ((domain != target_domain) && !info->domain_neutral)) {
2652 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2653 if (ji)
2654 *ji = info;
2655 return info->code_start;
2659 if (ji)
2660 *ji = NULL;
2661 return NULL;
2664 static guint32 bisect_opt = 0;
2665 static GHashTable *bisect_methods_hash = NULL;
2667 void
2668 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2670 FILE *file;
2671 char method_name [2048];
2673 bisect_opt = opt;
2674 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2675 g_assert (bisect_methods_hash);
2677 file = fopen (method_list_filename, "r");
2678 g_assert (file);
2680 while (fgets (method_name, sizeof (method_name), file)) {
2681 size_t len = strlen (method_name);
2682 g_assert (len > 0);
2683 g_assert (method_name [len - 1] == '\n');
2684 method_name [len - 1] = 0;
2685 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2687 g_assert (feof (file));
2690 gboolean mono_do_single_method_regression = FALSE;
2691 guint32 mono_single_method_regression_opt = 0;
2692 MonoMethod *mono_current_single_method;
2693 GSList *mono_single_method_list;
2694 GHashTable *mono_single_method_hash;
2696 guint32
2697 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2699 g_assert (method);
2701 if (bisect_methods_hash) {
2702 char *name = mono_method_full_name (method, TRUE);
2703 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2704 g_free (name);
2705 if (res)
2706 return default_opt | bisect_opt;
2708 if (!mono_do_single_method_regression)
2709 return default_opt;
2710 if (!mono_current_single_method) {
2711 if (!mono_single_method_hash)
2712 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2713 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2714 g_hash_table_insert (mono_single_method_hash, method, method);
2715 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2717 return default_opt;
2719 if (method == mono_current_single_method)
2720 return mono_single_method_regression_opt;
2721 return default_opt;
2724 gpointer
2725 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2727 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2730 typedef struct {
2731 MonoMethod *method;
2732 gpointer compiled_method;
2733 gpointer runtime_invoke;
2734 MonoVTable *vtable;
2735 MonoDynCallInfo *dyn_call_info;
2736 MonoClass *ret_box_class;
2737 MonoMethodSignature *sig;
2738 gboolean gsharedvt_invoke;
2739 gboolean use_interp;
2740 gpointer *wrapper_arg;
2741 } RuntimeInvokeInfo;
2743 static RuntimeInvokeInfo*
2744 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2746 MonoMethod *invoke;
2747 RuntimeInvokeInfo *info;
2749 info = g_new0 (RuntimeInvokeInfo, 1);
2750 info->compiled_method = compiled_method;
2751 info->use_interp = use_interp;
2752 if (mono_llvm_only && method->string_ctor)
2753 info->sig = mono_marshal_get_string_ctor_signature (method);
2754 else
2755 info->sig = mono_method_signature_internal (method);
2757 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2758 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2759 if (!mono_error_ok (error))
2760 return NULL;
2761 g_assert (info->vtable);
2763 MonoMethodSignature *sig = info->sig;
2764 MonoType *ret_type;
2767 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2768 * in full-aot mode, so we use a slower, but more generic wrapper if
2769 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2771 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2772 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2773 gboolean supported = TRUE;
2774 int i;
2776 if (method->string_ctor)
2777 sig = mono_marshal_get_string_ctor_signature (method);
2779 for (i = 0; i < sig->param_count; ++i) {
2780 MonoType *t = sig->params [i];
2782 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
2783 supported = FALSE;
2786 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2787 supported = FALSE;
2789 if (supported) {
2790 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2791 if (mini_debug_options.dyn_runtime_invoke)
2792 g_assert (info->dyn_call_info);
2795 #endif
2797 ret_type = sig->ret;
2798 switch (ret_type->type) {
2799 case MONO_TYPE_VOID:
2800 break;
2801 case MONO_TYPE_I1:
2802 case MONO_TYPE_U1:
2803 case MONO_TYPE_I2:
2804 case MONO_TYPE_U2:
2805 case MONO_TYPE_I4:
2806 case MONO_TYPE_U4:
2807 case MONO_TYPE_I:
2808 case MONO_TYPE_U:
2809 case MONO_TYPE_I8:
2810 case MONO_TYPE_U8:
2811 case MONO_TYPE_BOOLEAN:
2812 case MONO_TYPE_CHAR:
2813 case MONO_TYPE_R4:
2814 case MONO_TYPE_R8:
2815 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2816 break;
2817 case MONO_TYPE_PTR:
2818 info->ret_box_class = mono_defaults.int_class;
2819 break;
2820 case MONO_TYPE_STRING:
2821 case MONO_TYPE_CLASS:
2822 case MONO_TYPE_ARRAY:
2823 case MONO_TYPE_SZARRAY:
2824 case MONO_TYPE_OBJECT:
2825 break;
2826 case MONO_TYPE_GENERICINST:
2827 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2828 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2829 break;
2830 case MONO_TYPE_VALUETYPE:
2831 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2832 break;
2833 default:
2834 g_assert_not_reached ();
2835 break;
2838 if (info->use_interp)
2839 return info;
2841 if (!info->dyn_call_info) {
2842 if (mono_llvm_only) {
2843 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2844 g_assert_not_reached ();
2845 #endif
2846 info->gsharedvt_invoke = TRUE;
2847 if (!callee_gsharedvt) {
2848 /* Invoke a gsharedvt out wrapper instead */
2849 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2850 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2852 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2853 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2855 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2856 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2857 g_free (wrapper_sig);
2859 info->compiled_method = mono_jit_compile_method (wrapper, error);
2860 if (!mono_error_ok (error)) {
2861 g_free (info);
2862 return NULL;
2864 } else {
2865 /* Gsharedvt methods can be invoked the same way */
2866 /* The out wrapper has the same signature as the compiled gsharedvt method */
2867 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2869 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
2871 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2872 g_free (wrapper_sig);
2875 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2876 if (!mono_error_ok (error)) {
2877 g_free (info);
2878 return NULL;
2882 return info;
2885 static MonoObject*
2886 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2888 MonoMethodSignature *sig = info->sig;
2889 MonoDomain *domain = mono_domain_get ();
2890 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2891 gpointer *args;
2892 gpointer retval_ptr;
2893 guint8 retval [256];
2894 gpointer *param_refs;
2895 int i, pindex;
2897 error_init (error);
2899 g_assert (info->gsharedvt_invoke);
2902 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2903 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2904 * signatures, so we only have to generate runtime invoke wrappers for these
2905 * signatures.
2906 * This code also handles invocation of gsharedvt methods directly, no
2907 * out wrappers are used in that case.
2909 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2910 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2911 pindex = 0;
2913 * The runtime invoke wrappers expects pointers to primitive types, so have to
2914 * use indirections.
2916 if (sig->hasthis)
2917 args [pindex ++] = &obj;
2918 if (sig->ret->type != MONO_TYPE_VOID) {
2919 retval_ptr = (gpointer)&retval;
2920 args [pindex ++] = &retval_ptr;
2922 for (i = 0; i < sig->param_count; ++i) {
2923 MonoType *t = sig->params [i];
2925 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
2926 MonoClass *klass = mono_class_from_mono_type_internal (t);
2927 guint8 *nullable_buf;
2928 int size;
2930 size = mono_class_value_size (klass, NULL);
2931 nullable_buf = g_alloca (size);
2932 g_assert (nullable_buf);
2934 /* The argument pointed to by params [i] is either a boxed vtype or null */
2935 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2936 params [i] = nullable_buf;
2939 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2940 param_refs [i] = params [i];
2941 params [i] = &(param_refs [i]);
2943 args [pindex ++] = &params [i];
2945 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2946 args [pindex ++] = &info->wrapper_arg;
2948 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2950 runtime_invoke (NULL, args, exc, info->compiled_method);
2951 if (exc && *exc)
2952 return NULL;
2954 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2955 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2956 else
2957 return *(MonoObject**)retval;
2961 * mono_jit_runtime_invoke:
2962 * \param method: the method to invoke
2963 * \param obj: this pointer
2964 * \param params: array of parameter values.
2965 * \param exc: Set to the exception raised in the managed method.
2966 * \param error: error or caught exception object
2967 * If \p exc is NULL, \p error is thrown instead.
2968 * If coop is enabled, \p exc argument is ignored -
2969 * all exceptions are caught and propagated through \p error
2971 static MonoObject*
2972 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2974 MonoMethod *invoke, *callee;
2975 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2976 MonoDomain *domain = mono_domain_get ();
2977 MonoJitDomainInfo *domain_info;
2978 RuntimeInvokeInfo *info, *info2;
2979 MonoJitInfo *ji = NULL;
2980 gboolean callee_gsharedvt = FALSE;
2982 if (mono_ee_features.force_use_interpreter)
2983 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
2985 error_init (error);
2986 if (exc)
2987 *exc = NULL;
2989 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2990 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2991 return NULL;
2994 domain_info = domain_jit_info (domain);
2996 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2998 if (!info) {
2999 if (mono_security_core_clr_enabled ()) {
3001 * This might be redundant since mono_class_vtable () already does this,
3002 * but keep it just in case for moonlight.
3004 mono_class_setup_vtable (method->klass);
3005 if (mono_class_has_failure (method->klass)) {
3006 mono_error_set_for_class_failure (error, method->klass);
3007 if (exc)
3008 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3009 return NULL;
3013 gpointer compiled_method;
3015 callee = method;
3016 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3017 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3019 * Array Get/Set/Address methods. The JIT implements them using inline code
3020 * inside the runtime invoke wrappers, so no need to compile them.
3022 if (mono_aot_only) {
3024 * Call a wrapper, since the runtime invoke wrapper was not generated.
3026 MonoMethod *wrapper;
3028 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3029 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3030 callee = wrapper;
3031 } else {
3032 callee = NULL;
3036 gboolean use_interp = FALSE;
3038 if (callee) {
3039 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3040 if (!compiled_method) {
3041 g_assert (!mono_error_ok (error));
3043 if (mono_use_interpreter)
3044 use_interp = TRUE;
3045 else
3046 return NULL;
3047 } else {
3048 if (mono_llvm_only) {
3049 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3050 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3051 if (callee_gsharedvt)
3052 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3055 if (!callee_gsharedvt)
3056 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3058 } else {
3059 compiled_method = NULL;
3062 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3063 if (!mono_error_ok (error))
3064 return NULL;
3066 mono_domain_lock (domain);
3067 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3068 mono_domain_unlock (domain);
3069 if (info2) {
3070 g_free (info);
3071 info = info2;
3076 * We need this here because mono_marshal_get_runtime_invoke can place
3077 * the helper method in System.Object and not the target class.
3079 if (!mono_runtime_class_init_full (info->vtable, error)) {
3080 if (exc)
3081 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3082 return NULL;
3085 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3086 we always catch the exception and propagate it through the MonoError */
3087 gboolean catchExcInMonoError =
3088 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3089 MonoObject *invoke_exc = NULL;
3090 if (catchExcInMonoError)
3091 exc = &invoke_exc;
3093 /* The wrappers expect this to be initialized to NULL */
3094 if (exc)
3095 *exc = NULL;
3097 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3098 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3099 if (info->dyn_call_info) {
3100 if (!dyn_runtime_invoke) {
3101 mono_domain_lock (domain);
3103 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3104 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3105 if (!dyn_runtime_invoke && mono_use_interpreter) {
3106 info->use_interp = TRUE;
3107 info->dyn_call_info = NULL;
3108 } else if (!mono_error_ok (error)) {
3109 mono_domain_unlock (domain);
3110 return NULL;
3112 mono_domain_unlock (domain);
3115 if (info->dyn_call_info) {
3116 MonoMethodSignature *sig = mono_method_signature_internal (method);
3117 gpointer *args;
3118 int i, pindex, buf_size;
3119 guint8 *buf;
3120 guint8 retval [256];
3122 /* Convert the arguments to the format expected by start_dyn_call () */
3123 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3124 pindex = 0;
3125 if (sig->hasthis)
3126 args [pindex ++] = &obj;
3127 for (i = 0; i < sig->param_count; ++i) {
3128 MonoType *t = sig->params [i];
3130 if (t->byref) {
3131 args [pindex ++] = &params [i];
3132 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3133 args [pindex ++] = &params [i];
3134 } else {
3135 args [pindex ++] = params [i];
3139 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3141 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3142 buf = g_alloca (buf_size);
3143 memset (buf, 0, buf_size);
3144 g_assert (buf);
3146 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3148 dyn_runtime_invoke (buf, exc, info->compiled_method);
3149 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3151 if (catchExcInMonoError && *exc != NULL) {
3152 mono_error_set_exception_instance (error, (MonoException*) *exc);
3153 return NULL;
3156 if (info->ret_box_class)
3157 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3158 else
3159 return *(MonoObject**)retval;
3161 #endif
3163 if (info->use_interp) {
3164 error_init (error);
3165 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3168 MonoObject *result;
3170 if (mono_llvm_only) {
3171 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3172 if (!is_ok (error))
3173 return NULL;
3174 } else {
3175 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3177 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3179 if (catchExcInMonoError && *exc != NULL) {
3180 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3181 mono_error_set_exception_instance (error, (MonoException*) *exc);
3183 return result;
3186 typedef struct {
3187 MonoVTable *vtable;
3188 int slot;
3189 } IMTTrampInfo;
3191 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
3194 * mini_llvmonly_initial_imt_tramp:
3196 * This function is called the first time a call is made through an IMT trampoline.
3197 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
3199 static gpointer
3200 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3202 IMTTrampInfo *info = (IMTTrampInfo*)arg;
3203 IMTTrampFunc **imt;
3204 IMTTrampFunc *ftndesc;
3205 IMTTrampFunc func;
3207 mono_vtable_build_imt_slot (info->vtable, info->slot);
3209 imt = (IMTTrampFunc**)info->vtable;
3210 imt -= MONO_IMT_SIZE;
3212 /* Return what the real IMT trampoline returns */
3213 ftndesc = imt [info->slot];
3214 func = ftndesc [0];
3216 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
3217 /* Happens when the imt slot contains only a generic virtual method */
3218 return NULL;
3219 return func ((gpointer *)ftndesc [1], imt_method);
3222 /* This is called indirectly through an imt slot. */
3223 static gpointer
3224 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3226 int i = 0;
3228 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
3229 while (arg [i] && arg [i] != imt_method)
3230 i += 2;
3231 g_assert (arg [i]);
3233 return arg [i + 1];
3236 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
3237 static gpointer
3238 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
3240 //g_assert (arg [0] == imt_method);
3241 return arg [1];
3244 static gpointer
3245 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
3247 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
3248 if (arg [0] == imt_method)
3249 return arg [1];
3250 else
3251 return arg [3];
3254 static gpointer
3255 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
3257 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
3258 if (arg [0] == imt_method)
3259 return arg [1];
3260 else if (arg [2] == imt_method)
3261 return arg [3];
3262 else
3263 return arg [5];
3267 * A version of the imt trampoline used for generic virtual/variant iface methods.
3268 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
3269 * in the search table. The original JIT code had a 'fallback' trampoline it could
3270 * call, but we can't do that, so we just return NULL, and the compiled code
3271 * will handle it.
3273 static gpointer
3274 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3276 int i = 0;
3278 while (arg [i] && arg [i] != imt_method)
3279 i += 2;
3280 if (!arg [i])
3281 return NULL;
3283 return arg [i + 1];
3286 static gpointer
3287 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
3289 gpointer *buf;
3290 gpointer *res;
3291 int i, index, real_count;
3292 gboolean virtual_generic = FALSE;
3295 * Create an array which is passed to the imt trampoline functions.
3296 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
3299 real_count = 0;
3300 for (i = 0; i < count; ++i) {
3301 MonoIMTCheckItem *item = imt_entries [i];
3303 if (item->is_equals)
3304 real_count ++;
3305 if (item->has_target_code)
3306 virtual_generic = TRUE;
3310 * Initialize all vtable entries reachable from this imt slot, so the compiled
3311 * code doesn't have to check it.
3313 for (i = 0; i < count; ++i) {
3314 MonoIMTCheckItem *item = imt_entries [i];
3315 int vt_slot;
3317 if (!item->is_equals || item->has_target_code)
3318 continue;
3319 vt_slot = item->value.vtable_slot;
3320 mono_init_vtable_slot (vtable, vt_slot);
3323 /* Save the entries into an array */
3324 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
3325 index = 0;
3326 for (i = 0; i < count; ++i) {
3327 MonoIMTCheckItem *item = imt_entries [i];
3329 if (!item->is_equals)
3330 continue;
3332 g_assert (item->key);
3333 buf [(index * 2)] = item->key;
3334 if (item->has_target_code)
3335 buf [(index * 2) + 1] = item->value.target_code;
3336 else
3337 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
3338 index ++;
3340 buf [(index * 2)] = NULL;
3341 buf [(index * 2) + 1] = fail_tramp;
3344 * Return a function descriptor for a C function with 'buf' as its argument.
3345 * It will by called by JITted code.
3347 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
3348 switch (real_count) {
3349 case 1:
3350 res [0] = (gpointer)mono_llvmonly_imt_tramp_1;
3351 break;
3352 case 2:
3353 res [0] = (gpointer)mono_llvmonly_imt_tramp_2;
3354 break;
3355 case 3:
3356 res [0] = (gpointer)mono_llvmonly_imt_tramp_3;
3357 break;
3358 default:
3359 res [0] = (gpointer)mono_llvmonly_imt_tramp;
3360 break;
3362 if (virtual_generic || fail_tramp)
3363 res [0] = (gpointer)mono_llvmonly_fallback_imt_tramp;
3364 res [1] = buf;
3366 return res;
3369 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3371 MonoException *exc = NULL;
3372 MonoJitInfo *ji;
3373 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3374 MONO_SIG_HANDLER_GET_CONTEXT;
3376 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3378 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3380 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3381 if (mono_arch_is_int_overflow (ctx, info))
3383 * The spec says this throws ArithmeticException, but MS throws the derived
3384 * OverflowException.
3386 exc = mono_get_exception_overflow ();
3387 else
3388 exc = mono_get_exception_divide_by_zero ();
3389 #else
3390 exc = mono_get_exception_divide_by_zero ();
3391 #endif
3393 if (!ji) {
3394 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3395 goto exit;
3397 mono_handle_native_crash ("SIGFPE", ctx, info);
3398 if (mono_do_crash_chaining) {
3399 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3400 goto exit;
3404 mono_arch_handle_exception (ctx, exc);
3406 exit:
3407 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3410 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3412 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3413 MONO_SIG_HANDLER_GET_CONTEXT;
3415 if (mono_runtime_get_no_exec ())
3416 exit (1);
3419 mono_handle_native_crash ("SIGILL", ctx, info);
3420 if (mono_do_crash_chaining) {
3421 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3422 return;
3425 g_assert_not_reached ();
3428 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3430 #define HAVE_SIG_INFO
3431 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3433 #ifdef MONO_SIG_HANDLER_DEBUG
3434 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3435 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3436 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3437 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3438 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3439 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3440 #endif
3442 #endif
3444 static gboolean
3445 is_addr_implicit_null_check (void *addr)
3447 /* implicit null checks are only expected to work on the first page. larger
3448 * offsets are expected to have an explicit null check */
3449 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3452 // This function is separate from mono_sigsegv_signal_handler
3453 // so debug_fault_addr can be seen in debugger stacks.
3454 #ifdef MONO_SIG_HANDLER_DEBUG
3455 MONO_NEVER_INLINE
3456 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3457 #else
3458 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3459 #endif
3461 MonoJitInfo *ji;
3462 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3463 gpointer fault_addr = NULL;
3464 #ifdef HAVE_SIG_INFO
3465 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3466 #else
3467 void *info = NULL;
3468 #endif
3469 MONO_SIG_HANDLER_GET_CONTEXT;
3471 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3472 if (mono_arch_is_single_step_event (info, ctx)) {
3473 mini_get_dbg_callbacks ()->single_step_event (ctx);
3474 return;
3475 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3476 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3477 return;
3479 #endif
3481 #if defined(HAVE_SIG_INFO)
3482 #if !defined(HOST_WIN32)
3483 fault_addr = info->si_addr;
3484 if (mono_aot_is_pagefault (info->si_addr)) {
3485 mono_aot_handle_pagefault (info->si_addr);
3486 return;
3488 #endif
3490 /* The thread might no be registered with the runtime */
3491 if (!mono_domain_get () || !jit_tls) {
3492 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3493 return;
3494 mono_handle_native_crash ("SIGSEGV", ctx, info);
3495 if (mono_do_crash_chaining) {
3496 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3497 return;
3500 #endif
3502 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3504 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3505 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3506 return;
3508 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3509 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3510 fault_addr = info->si_addr;
3511 if (fault_addr == NULL) {
3512 MonoContext mctx;
3514 mono_sigctx_to_monoctx (ctx, &mctx);
3516 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3518 #endif
3520 if (jit_tls->stack_size &&
3521 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3523 * The hard-guard page has been hit: there is not much we can do anymore
3524 * Print a hopefully clear message and abort.
3526 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3527 g_assert_not_reached ();
3528 } else {
3529 /* The original handler might not like that it is executed on an altstack... */
3530 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3531 return;
3533 if (is_addr_implicit_null_check (info->si_addr)) {
3534 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3535 } else {
3536 mono_handle_native_crash ("SIGSEGV", ctx, info);
3539 #else
3541 if (!ji) {
3542 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3543 return;
3545 mono_handle_native_crash ("SIGSEGV", ctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3547 if (mono_do_crash_chaining) {
3548 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3549 return;
3553 if (is_addr_implicit_null_check (fault_addr)) {
3554 mono_arch_handle_exception (ctx, NULL);
3555 } else {
3556 mono_handle_native_crash ("SIGSEGV", ctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3558 #endif
3561 #ifdef MONO_SIG_HANDLER_DEBUG
3563 // This function is separate from mono_sigsegv_signal_handler_debug
3564 // so debug_fault_addr can be seen in debugger stacks.
3565 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3567 #ifdef HOST_WIN32
3568 gpointer const debug_fault_addr = (gpointer)_info->ExceptionRecord->ExceptionInformation [1];
3569 #elif defined (HAVE_SIG_INFO)
3570 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3571 #else
3572 #error No extra parameter is passed, not even 0, to avoid any confusion.
3573 #endif
3574 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3577 #endif // MONO_SIG_HANDLER_DEBUG
3579 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3581 MonoException *exc;
3582 MONO_SIG_HANDLER_GET_CONTEXT;
3584 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3586 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3588 mono_arch_handle_exception (ctx, exc);
3590 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3593 #ifndef DISABLE_REMOTING
3594 /* mono_jit_create_remoting_trampoline:
3595 * @method: pointer to the method info
3597 * Creates a trampoline which calls the remoting functions. This
3598 * is used in the vtable of transparent proxies.
3600 * Returns: a pointer to the newly created code
3602 static gpointer
3603 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3605 MonoMethod *nm;
3606 guint8 *addr = NULL;
3608 error_init (error);
3610 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3611 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3612 domain, NULL);
3615 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3616 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3617 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3618 else
3619 nm = method;
3620 return_val_if_nok (error, NULL);
3621 addr = (guint8 *)mono_compile_method_checked (nm, error);
3622 return_val_if_nok (error, NULL);
3623 return mono_get_addr_from_ftnptr (addr);
3625 #endif
3627 static G_GNUC_UNUSED void
3628 no_imt_trampoline (void)
3630 g_assert_not_reached ();
3633 static G_GNUC_UNUSED void
3634 no_vcall_trampoline (void)
3636 g_assert_not_reached ();
3639 static gpointer *vtable_trampolines;
3640 static int vtable_trampolines_size;
3642 gpointer
3643 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3645 int index = slot_index + MONO_IMT_SIZE;
3647 if (mono_llvm_only) {
3648 if (slot_index < 0) {
3649 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3650 // FIXME: Memory management
3651 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3652 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3653 info->vtable = vt;
3654 info->slot = index;
3655 ftndesc [0] = (gpointer)mini_llvmonly_initial_imt_tramp;
3656 ftndesc [1] = info;
3657 mono_memory_barrier ();
3658 return ftndesc;
3659 } else {
3660 return NULL;
3664 g_assert (slot_index >= - MONO_IMT_SIZE);
3665 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3666 mono_jit_lock ();
3667 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3668 int new_size;
3669 gpointer new_table;
3671 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3672 while (new_size <= index)
3673 new_size *= 2;
3674 new_table = g_new0 (gpointer, new_size);
3676 if (vtable_trampolines)
3677 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3678 g_free (vtable_trampolines);
3679 mono_memory_barrier ();
3680 vtable_trampolines = (void **)new_table;
3681 vtable_trampolines_size = new_size;
3683 mono_jit_unlock ();
3686 if (!vtable_trampolines [index])
3687 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3688 return vtable_trampolines [index];
3691 static gpointer
3692 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3694 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3697 static gboolean
3698 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3700 if (mono_llvm_only)
3701 return FALSE;
3703 gpointer *imt = (gpointer*)vt;
3704 imt -= MONO_IMT_SIZE;
3706 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3709 static gboolean
3710 is_callee_gsharedvt_variable (gpointer addr)
3712 MonoJitInfo *ji;
3713 gboolean callee_gsharedvt;
3715 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3716 g_assert (ji);
3717 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3718 if (callee_gsharedvt)
3719 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3720 return callee_gsharedvt;
3723 gpointer
3724 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3726 gpointer arg = NULL;
3728 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3729 arg = mini_method_get_rgctx (method);
3732 * Avoid adding gsharedvt in wrappers since they might not exist if
3733 * this delegate is called through a gsharedvt delegate invoke wrapper.
3734 * Instead, encode that the method is gsharedvt in del->extra_arg,
3735 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3737 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3738 g_assert ((((gsize)arg) & 1) == 0);
3739 arg = (gpointer)(((gsize)arg) | 1);
3741 return arg;
3744 void
3745 mini_init_delegate (MonoDelegate *del)
3747 if (mono_use_interpreter)
3748 mini_get_interp_callbacks ()->init_delegate (del);
3749 else if (mono_llvm_only)
3750 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3753 char*
3754 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3756 int abs_offset;
3758 abs_offset = offset;
3759 if (abs_offset < 0)
3760 abs_offset = - abs_offset;
3761 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3764 gpointer
3765 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3767 gboolean is_virtual_generic, is_interface, load_imt_reg;
3768 int offset, idx;
3770 static guint8 **cache = NULL;
3771 static int cache_size = 0;
3773 if (!method)
3774 return NULL;
3776 if (MONO_TYPE_ISSTRUCT (sig->ret))
3777 return NULL;
3779 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3780 is_interface = mono_class_is_interface (method->klass);
3781 load_imt_reg = is_virtual_generic || is_interface;
3783 if (is_interface)
3784 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3785 else
3786 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3788 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3789 g_assert (idx >= 0);
3791 /* Resize the cache to idx + 1 */
3792 if (cache_size < idx + 1) {
3793 mono_jit_lock ();
3794 if (cache_size < idx + 1) {
3795 guint8 **new_cache;
3796 int new_cache_size = idx + 1;
3798 new_cache = g_new0 (guint8*, new_cache_size);
3799 if (cache)
3800 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3801 g_free (cache);
3803 mono_memory_barrier ();
3804 cache = new_cache;
3805 cache_size = new_cache_size;
3807 mono_jit_unlock ();
3810 if (cache [idx])
3811 return cache [idx];
3813 /* FIXME Support more cases */
3814 if (mono_ee_features.use_aot_trampolines) {
3815 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3816 g_assert (cache [idx]);
3817 } else {
3818 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3820 return cache [idx];
3824 * mini_parse_debug_option:
3825 * @option: The option to parse.
3827 * Parses debug options for the mono runtime. The options are the same as for
3828 * the MONO_DEBUG environment variable.
3831 gboolean
3832 mini_parse_debug_option (const char *option)
3834 // Empty string is ok as consequence of appending ",foo"
3835 // without first checking for empty.
3836 if (*option == 0)
3837 return TRUE;
3839 if (!strcmp (option, "handle-sigint"))
3840 mini_debug_options.handle_sigint = TRUE;
3841 else if (!strcmp (option, "keep-delegates"))
3842 mini_debug_options.keep_delegates = TRUE;
3843 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3844 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3845 else if (!strcmp (option, "collect-pagefault-stats"))
3846 mini_debug_options.collect_pagefault_stats = TRUE;
3847 else if (!strcmp (option, "break-on-unverified"))
3848 mini_debug_options.break_on_unverified = TRUE;
3849 else if (!strcmp (option, "no-gdb-backtrace"))
3850 mini_debug_options.no_gdb_backtrace = TRUE;
3851 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3852 mini_debug_options.suspend_on_native_crash = TRUE;
3853 else if (!strcmp (option, "suspend-on-exception"))
3854 mini_debug_options.suspend_on_exception = TRUE;
3855 else if (!strcmp (option, "suspend-on-unhandled"))
3856 mini_debug_options.suspend_on_unhandled = TRUE;
3857 else if (!strcmp (option, "dont-free-domains"))
3858 mono_dont_free_domains = TRUE;
3859 else if (!strcmp (option, "dyn-runtime-invoke"))
3860 mini_debug_options.dyn_runtime_invoke = TRUE;
3861 else if (!strcmp (option, "gdb"))
3862 mini_debug_options.gdb = TRUE;
3863 else if (!strcmp (option, "lldb"))
3864 mini_debug_options.lldb = TRUE;
3865 else if (!strcmp (option, "explicit-null-checks"))
3866 mini_debug_options.explicit_null_checks = TRUE;
3867 else if (!strcmp (option, "gen-seq-points"))
3868 mini_debug_options.gen_sdb_seq_points = TRUE;
3869 else if (!strcmp (option, "gen-compact-seq-points"))
3870 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3871 else if (!strcmp (option, "no-compact-seq-points"))
3872 mini_debug_options.no_seq_points_compact_data = TRUE;
3873 else if (!strcmp (option, "single-imm-size"))
3874 mini_debug_options.single_imm_size = TRUE;
3875 else if (!strcmp (option, "init-stacks"))
3876 mini_debug_options.init_stacks = TRUE;
3877 else if (!strcmp (option, "casts"))
3878 mini_debug_options.better_cast_details = TRUE;
3879 else if (!strcmp (option, "soft-breakpoints"))
3880 mini_debug_options.soft_breakpoints = TRUE;
3881 else if (!strcmp (option, "check-pinvoke-callconv"))
3882 mini_debug_options.check_pinvoke_callconv = TRUE;
3883 else if (!strcmp (option, "use-fallback-tls"))
3884 mini_debug_options.use_fallback_tls = TRUE;
3885 else if (!strcmp (option, "debug-domain-unload"))
3886 mono_enable_debug_domain_unload (TRUE);
3887 else if (!strcmp (option, "partial-sharing"))
3888 mono_set_partial_sharing_supported (TRUE);
3889 else if (!strcmp (option, "align-small-structs"))
3890 mono_align_small_structs = TRUE;
3891 else if (!strcmp (option, "native-debugger-break"))
3892 mini_debug_options.native_debugger_break = TRUE;
3893 else if (!strcmp (option, "disable_omit_fp"))
3894 mini_debug_options.disable_omit_fp = TRUE;
3895 // This is an internal testing feature.
3896 // Every tail. encountered is required to be optimized.
3897 // It is asserted.
3898 else if (!strcmp (option, "test-tailcall-require"))
3899 mini_debug_options.test_tailcall_require = TRUE;
3900 else if (!strcmp (option, "verbose-gdb"))
3901 mini_debug_options.verbose_gdb = TRUE;
3902 else if (!strncmp (option, "thread-dump-dir=", 16))
3903 mono_set_thread_dump_dir(g_strdup(option + 16));
3904 else if (!strncmp (option, "aot-skip=", 9)) {
3905 mini_debug_options.aot_skip_set = TRUE;
3906 mini_debug_options.aot_skip = atoi (option + 9);
3907 } else
3908 return FALSE;
3910 return TRUE;
3913 static void
3914 mini_parse_debug_options (void)
3916 char *options = g_getenv ("MONO_DEBUG");
3917 gchar **args, **ptr;
3919 if (!options)
3920 return;
3922 args = g_strsplit (options, ",", -1);
3923 g_free (options);
3925 for (ptr = args; ptr && *ptr; ptr++) {
3926 const char *arg = *ptr;
3928 if (!mini_parse_debug_option (arg)) {
3929 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3930 // test-tailcall-require is also accepted but not documented.
3931 // empty string is also accepted and ignored as a consequence
3932 // of appending ",foo" without checking for empty.
3933 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");
3934 exit (1);
3938 g_strfreev (args);
3941 MonoDebugOptions *
3942 mini_get_debug_options (void)
3944 return &mini_debug_options;
3947 static gpointer
3948 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3950 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3951 gpointer* desc = NULL;
3953 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3954 return desc;
3955 #if defined(__mono_ppc64__)
3956 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3958 desc [0] = addr;
3959 desc [1] = NULL;
3960 desc [2] = NULL;
3961 # endif
3962 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3963 return desc;
3964 #else
3965 return addr;
3966 #endif
3969 static gpointer
3970 mini_get_addr_from_ftnptr (gpointer descr)
3972 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3973 return *(gpointer*)descr;
3974 #else
3975 return descr;
3976 #endif
3979 static void
3980 register_jit_stats (void)
3982 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3983 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3984 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3985 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3986 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
3987 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3988 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3989 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);
3990 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3991 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3992 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3993 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3994 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3995 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3996 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3997 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3998 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3999 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
4000 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
4001 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
4002 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
4003 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
4004 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
4005 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
4006 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
4007 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
4008 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
4009 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
4010 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
4011 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
4012 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
4013 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
4014 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
4015 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
4016 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
4017 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
4018 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
4019 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
4020 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
4021 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
4022 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
4023 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
4024 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
4025 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
4026 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
4027 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
4028 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
4029 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
4030 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
4031 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
4032 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
4033 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
4034 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
4035 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
4036 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
4037 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
4038 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
4039 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
4040 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
4041 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
4042 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
4043 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
4046 static void runtime_invoke_info_free (gpointer value);
4048 static gint
4049 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
4051 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
4052 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
4054 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
4057 static guint
4058 class_method_pair_hash (gconstpointer data)
4060 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
4062 return (gsize)pair->klass ^ (gsize)pair->method;
4065 static void
4066 mini_create_jit_domain_info (MonoDomain *domain)
4068 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
4070 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4071 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4072 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
4073 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
4074 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
4075 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
4076 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
4077 info->jump_target_hash = g_hash_table_new (NULL, NULL);
4078 mono_jit_code_hash_init (&info->interp_code_hash);
4080 domain->runtime_info = info;
4083 static void
4084 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
4086 MonoJumpList *jlist = (MonoJumpList *)value;
4087 g_slist_free ((GSList*)jlist->list);
4090 static void
4091 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
4093 GSList *list = (GSList *)value;
4094 g_slist_free (list);
4097 static void
4098 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
4100 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
4101 mono_code_manager_destroy (di->code_mp);
4102 g_free (di);
4105 static void
4106 runtime_invoke_info_free (gpointer value)
4108 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
4110 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4111 if (info->dyn_call_info)
4112 mono_arch_dyn_call_free (info->dyn_call_info);
4113 #endif
4114 g_free (info);
4117 static void
4118 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
4120 g_slist_free ((GSList*)value);
4123 static void
4124 mini_free_jit_domain_info (MonoDomain *domain)
4126 MonoJitDomainInfo *info = domain_jit_info (domain);
4128 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
4129 g_hash_table_destroy (info->jump_target_hash);
4130 if (info->jump_target_got_slot_hash) {
4131 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
4132 g_hash_table_destroy (info->jump_target_got_slot_hash);
4134 if (info->dynamic_code_hash) {
4135 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
4136 g_hash_table_destroy (info->dynamic_code_hash);
4138 g_hash_table_destroy (info->method_code_hash);
4139 g_hash_table_destroy (info->jump_trampoline_hash);
4140 g_hash_table_destroy (info->jit_trampoline_hash);
4141 g_hash_table_destroy (info->delegate_trampoline_hash);
4142 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
4143 g_hash_table_destroy (info->mrgctx_hash);
4144 g_hash_table_destroy (info->method_rgctx_hash);
4145 g_hash_table_destroy (info->interp_method_pointer_hash);
4146 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
4147 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
4148 g_hash_table_destroy (info->seq_points);
4149 g_hash_table_destroy (info->arch_seq_points);
4150 if (info->agent_info)
4151 mini_get_dbg_callbacks ()->free_domain_info (domain);
4152 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
4153 if (info->llvm_jit_callees) {
4154 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
4155 g_hash_table_destroy (info->llvm_jit_callees);
4157 mono_internal_hash_table_destroy (&info->interp_code_hash);
4158 #ifdef ENABLE_LLVM
4159 mono_llvm_free_domain_info (domain);
4160 #endif
4162 g_free (domain->runtime_info);
4163 domain->runtime_info = NULL;
4166 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4168 static void
4169 code_manager_chunk_new (void *chunk, int size)
4171 mono_arch_code_chunk_new (chunk, size);
4174 static void
4175 code_manager_chunk_destroy (void *chunk)
4177 mono_arch_code_chunk_destroy (chunk);
4180 #endif
4182 #ifdef ENABLE_LLVM
4183 static gboolean
4184 llvm_init_inner (void)
4186 if (!mono_llvm_load (NULL))
4187 return FALSE;
4189 mono_llvm_init ();
4190 return TRUE;
4192 #endif
4195 * mini_llvm_init:
4197 * Load and initialize LLVM support.
4198 * Return TRUE on success.
4200 gboolean
4201 mini_llvm_init (void)
4203 #ifdef ENABLE_LLVM
4204 static gboolean llvm_inited;
4205 static gboolean init_result;
4207 mono_loader_lock_if_inited ();
4208 if (!llvm_inited) {
4209 init_result = llvm_init_inner ();
4210 llvm_inited = TRUE;
4212 mono_loader_unlock_if_inited ();
4213 return init_result;
4214 #else
4215 return FALSE;
4216 #endif
4219 void
4220 mini_add_profiler_argument (const char *desc)
4222 if (!profile_options)
4223 profile_options = g_ptr_array_new ();
4225 g_ptr_array_add (profile_options, (gpointer) desc);
4229 static MonoEECallbacks interp_cbs = {0};
4231 void
4232 mini_install_interp_callbacks (MonoEECallbacks *cbs)
4234 memcpy (&interp_cbs, cbs, sizeof (MonoEECallbacks));
4237 MonoEECallbacks *
4238 mini_get_interp_callbacks (void)
4240 return &interp_cbs;
4243 static MonoDebuggerCallbacks dbg_cbs;
4245 void
4246 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4248 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4249 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4252 MonoDebuggerCallbacks*
4253 mini_get_dbg_callbacks (void)
4255 return &dbg_cbs;
4259 mono_ee_api_version (void)
4261 return MONO_EE_API_VERSION;
4264 void
4265 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4267 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4270 MonoDomain *
4271 mini_init (const char *filename, const char *runtime_version)
4273 ERROR_DECL (error);
4274 MonoDomain *domain;
4275 MonoRuntimeCallbacks callbacks;
4276 MonoThreadInfoRuntimeCallbacks ticallbacks;
4277 MonoCodeManagerCallbacks code_manager_callbacks;
4279 MONO_VES_INIT_BEGIN ();
4281 CHECKED_MONO_INIT ();
4283 #if defined(__linux__)
4284 if (access ("/proc/self/maps", F_OK) != 0) {
4285 g_print ("Mono requires /proc to be mounted.\n");
4286 exit (1);
4288 #endif
4290 mono_interp_stub_init ();
4291 #ifndef DISABLE_INTERPRETER
4292 if (mono_use_interpreter)
4293 mono_ee_interp_init (mono_interp_opts_string);
4294 #endif
4296 mono_debugger_agent_stub_init ();
4297 #ifndef DISABLE_SDB
4298 mono_debugger_agent_init ();
4299 #endif
4301 if (sdb_options)
4302 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4304 mono_os_mutex_init_recursive (&jit_mutex);
4306 mono_cross_helpers_run ();
4308 mono_counters_init ();
4310 mini_jit_init ();
4312 mini_jit_init_job_control ();
4314 /* Happens when using the embedding interface */
4315 if (!default_opt_set)
4316 default_opt = mono_parse_default_optimizations (NULL);
4318 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4319 if (mono_aot_only)
4320 mono_set_generic_sharing_vt_supported (TRUE);
4321 #else
4322 if (mono_llvm_only)
4323 mono_set_generic_sharing_vt_supported (TRUE);
4324 #endif
4326 mono_tls_init_runtime_keys ();
4328 if (!global_codeman)
4329 global_codeman = mono_code_manager_new ();
4331 memset (&callbacks, 0, sizeof (callbacks));
4332 callbacks.create_ftnptr = mini_create_ftnptr;
4333 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4334 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4335 callbacks.set_cast_details = mono_set_cast_details;
4336 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4337 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4338 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4339 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4340 callbacks.imt_entry_inited = mini_imt_entry_inited;
4341 callbacks.init_delegate = mini_init_delegate;
4342 #define JIT_INVOKE_WORKS
4343 #ifdef JIT_INVOKE_WORKS
4344 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4345 #endif
4346 #define JIT_TRAMPOLINES_WORK
4347 #ifdef JIT_TRAMPOLINES_WORK
4348 callbacks.compile_method = mono_jit_compile_method;
4349 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4350 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4351 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4352 callbacks.free_method = mono_jit_free_method;
4353 #ifndef DISABLE_REMOTING
4354 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4355 #endif
4356 #endif
4357 #ifndef DISABLE_REMOTING
4358 if (mono_use_interpreter)
4359 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4360 #endif
4361 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4363 #ifndef DISABLE_CRASH_REPORTING
4364 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4365 #endif
4367 mono_install_callbacks (&callbacks);
4369 memset (&ticallbacks, 0, sizeof (ticallbacks));
4370 ticallbacks.setup_async_callback = mono_setup_async_callback;
4371 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
4372 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
4373 ticallbacks.thread_state_init = mono_thread_state_init;
4375 #ifndef HOST_WIN32
4376 mono_w32handle_init ();
4377 #endif
4379 mono_thread_info_runtime_init (&ticallbacks);
4381 if (g_hasenv ("MONO_DEBUG")) {
4382 mini_parse_debug_options ();
4385 mono_code_manager_init ();
4387 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
4388 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4389 code_manager_callbacks.chunk_new = code_manager_chunk_new;
4390 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
4391 #endif
4392 mono_code_manager_install_callbacks (&code_manager_callbacks);
4394 mono_hwcap_init ();
4396 mono_arch_cpu_init ();
4398 mono_arch_init ();
4400 mono_unwind_init ();
4402 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
4403 mono_lldb_init ("");
4404 mono_dont_free_domains = TRUE;
4407 #ifdef XDEBUG_ENABLED
4408 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4409 if (mono_xdebug) {
4410 mono_xdebug_init (mono_xdebug);
4411 g_free (mono_xdebug);
4412 /* So methods for multiple domains don't have the same address */
4413 mono_dont_free_domains = TRUE;
4414 mono_using_xdebug = TRUE;
4415 } else if (mini_get_debug_options ()->gdb) {
4416 mono_xdebug_init ((char*)"gdb");
4417 mono_dont_free_domains = TRUE;
4418 mono_using_xdebug = TRUE;
4420 #endif
4422 #ifdef ENABLE_LLVM
4423 if (mono_use_llvm) {
4424 if (!mono_llvm_load (NULL)) {
4425 mono_use_llvm = FALSE;
4426 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4429 if (mono_use_llvm)
4430 mono_llvm_init ();
4431 #endif
4433 mono_trampolines_init ();
4435 if (default_opt & MONO_OPT_AOT)
4436 mono_aot_init ();
4438 mini_get_dbg_callbacks ()->init ();
4440 #ifdef TARGET_WASM
4441 mono_wasm_debugger_init ();
4442 #endif
4444 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4445 mono_set_generic_sharing_supported (TRUE);
4446 #endif
4448 mono_thread_info_signals_init ();
4450 #ifndef MONO_CROSS_COMPILE
4451 mono_runtime_install_handlers ();
4452 #endif
4453 mono_threads_install_cleanup (mini_thread_cleanup);
4455 #ifdef JIT_TRAMPOLINES_WORK
4456 mono_install_create_domain_hook (mini_create_jit_domain_info);
4457 mono_install_free_domain_hook (mini_free_jit_domain_info);
4458 #endif
4459 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4460 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4461 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4463 mono_profiler_state.context_enable = mini_profiler_context_enable;
4464 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4465 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4466 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4467 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4468 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4470 if (profile_options)
4471 for (guint i = 0; i < profile_options->len; i++)
4472 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4474 mono_profiler_started ();
4476 if (mini_debug_options.collect_pagefault_stats)
4477 mono_aot_set_make_unreadable (TRUE);
4479 if (runtime_version)
4480 domain = mono_init_version (filename, runtime_version);
4481 else
4482 domain = mono_init_from_assembly (filename, filename);
4484 if (mono_aot_only) {
4485 /* This helps catch code allocation requests */
4486 mono_code_manager_set_read_only (domain->code_mp);
4487 mono_marshal_use_aot_wrappers (TRUE);
4490 if (mono_llvm_only) {
4491 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
4492 mono_set_always_build_imt_trampolines (TRUE);
4493 } else if (mono_aot_only) {
4494 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4495 } else {
4496 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4499 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4500 mono_arch_finish_init ();
4502 mono_icall_init ();
4504 /* This must come after mono_init () in the aot-only case */
4505 mono_exceptions_init ();
4507 /* This should come after mono_init () too */
4508 mini_gc_init ();
4510 #ifndef DISABLE_JIT
4511 mono_create_helper_signatures ();
4512 #endif
4514 register_jit_stats ();
4516 #define JIT_CALLS_WORK
4517 #ifdef JIT_CALLS_WORK
4518 /* Needs to be called here since register_jit_icall depends on it */
4519 mono_marshal_init ();
4521 mono_arch_register_lowlevel_calls ();
4523 register_icalls ();
4525 mono_generic_sharing_init ();
4526 #endif
4528 #ifdef MONO_ARCH_SIMD_INTRINSICS
4529 mono_simd_intrinsics_init ();
4530 #endif
4532 mono_tasklets_init ();
4534 register_trampolines (domain);
4536 if (mono_compile_aot)
4538 * Avoid running managed code when AOT compiling, since the platform
4539 * might only support aot-only execution.
4541 mono_runtime_set_no_exec (TRUE);
4543 mono_mem_account_register_counters ();
4545 #define JIT_RUNTIME_WORKS
4546 #ifdef JIT_RUNTIME_WORKS
4547 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4548 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4549 mono_error_assert_ok (error);
4550 mono_thread_attach (domain);
4551 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4552 #endif
4554 if (mono_profiler_sampling_enabled ())
4555 mono_runtime_setup_stat_profiler ();
4557 MONO_PROFILER_RAISE (runtime_initialized, ());
4559 MONO_VES_INIT_END ();
4561 return domain;
4564 #ifdef MONO_ARCH_EMULATE_FREM
4565 // Wrapper to avoid taking address of overloaded function.
4566 static double
4567 mono_fmod (double a, double b)
4569 return fmod (a, b);
4571 #endif
4573 static void
4574 register_icalls (void)
4576 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4577 ves_icall_get_frame_info);
4578 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4579 ves_icall_get_trace);
4580 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4581 mono_runtime_install_handlers);
4582 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4583 mono_runtime_cleanup_handlers);
4585 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4586 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4587 mini_get_dbg_callbacks ()->unhandled_exception);
4588 #endif
4591 * It's important that we pass `TRUE` as the last argument here, as
4592 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4593 * *did* emit a wrapper, we'd be looking at infinite recursion since
4594 * the wrapper would call the icall which would call the wrapper and
4595 * so on.
4597 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4598 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4599 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4600 register_icall (mono_profiler_raise_exception_clause, "mono_profiler_raise_exception_clause", "void ptr int int object", TRUE);
4602 register_icall (mono_trace_enter_method, "mono_trace_enter_method", "void ptr ptr", TRUE);
4603 register_icall (mono_trace_leave_method, "mono_trace_leave_method", "void ptr ptr", TRUE);
4604 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4605 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4606 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4608 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4609 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4610 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4611 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int ptr object", TRUE);
4612 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4613 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4614 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4615 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4616 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4618 // FIXME: This is broken
4619 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4620 #endif
4622 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4623 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4624 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4625 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4626 register_icall (ves_icall_thread_finish_async_abort, "ves_icall_thread_finish_async_abort", "void", FALSE);
4627 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4628 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4630 if (mono_threads_are_safepoints_enabled ())
4631 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4633 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4634 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4635 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4636 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4637 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4638 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4639 #endif
4640 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4641 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4642 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4643 #endif
4645 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4646 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4647 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4648 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4649 #endif
4651 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4652 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4653 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4654 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4655 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4656 #endif
4658 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4659 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4660 #endif
4662 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4663 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4664 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4665 #endif
4667 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4668 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4669 #endif
4671 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4672 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4673 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4674 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4675 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4676 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4677 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4680 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4681 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4682 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4683 #endif
4685 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4686 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);
4687 #endif
4688 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4689 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4690 #endif
4691 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4692 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4693 #endif
4694 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4695 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);
4696 #endif
4697 #ifdef MONO_ARCH_EMULATE_FREM
4698 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "fmod", FALSE);
4699 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4700 #endif
4702 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4703 if (mono_arch_is_soft_float ()) {
4704 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4705 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4706 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4707 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4708 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4709 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4710 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4711 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4712 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4713 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4714 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4715 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4717 #if TARGET_SIZEOF_VOID_P == 4
4718 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4719 #endif
4721 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4722 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4723 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4724 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4725 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4726 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4727 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4728 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4729 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4730 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4732 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4733 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4734 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4735 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4736 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4738 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4739 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4740 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4741 register_icall (mono_isfinite_double, "mono_isfinite_double", "int32 double", FALSE);
4743 #endif
4744 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4746 #ifdef COMPRESSED_INTERFACE_BITMAP
4747 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4748 #endif
4750 #if SIZEOF_REGISTER == 4
4751 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4752 #else
4753 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4754 #endif
4756 /* other jit icalls */
4757 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4758 register_icall (ves_icall_mono_delegate_ctor_interp, "ves_icall_mono_delegate_ctor_interp", "void object object ptr", FALSE);
4759 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4760 "ptr ptr ptr", FALSE);
4761 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4762 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4763 "ptr ptr ptr ptr", FALSE);
4764 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4765 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4766 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4767 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4768 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4769 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4770 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4771 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4772 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4773 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4774 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4775 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4776 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4777 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4778 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4779 register_icall (mono_value_copy_internal, "mono_value_copy_internal", "void ptr ptr ptr", FALSE);
4780 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4781 register_icall (mono_break, "mono_break", NULL, TRUE);
4782 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4783 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4784 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4785 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4786 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4787 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4788 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4789 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4790 register_icall (mono_resume_unwind, "mono_resume_unwind", "void ptr", TRUE);
4791 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4792 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4794 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4795 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4797 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4798 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4799 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4800 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4801 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4803 register_icall (mini_get_dbg_callbacks ()->user_break, "mono_debugger_agent_user_break", "void", FALSE);
4805 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4806 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4807 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4808 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4810 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4811 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4812 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4813 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4814 /* This needs a wrapper so it can have a preserveall cconv */
4815 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4816 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4817 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4818 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4819 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4820 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4821 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4823 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "int32 obj");
4824 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4825 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4826 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4828 #ifdef TARGET_IOS
4829 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4830 #endif
4831 /* Register tls icalls */
4832 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4833 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4834 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4835 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4836 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4837 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4838 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4839 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4840 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4841 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4843 register_icall_no_wrapper (mono_interp_entry_from_trampoline, "mono_interp_entry_from_trampoline", "void ptr ptr");
4845 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4846 mono_arch_register_icall ();
4847 #endif
4850 MonoJitStats mono_jit_stats = {0};
4853 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4854 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4856 MONO_NO_SANITIZE_THREAD
4857 static void
4858 print_jit_stats (void)
4860 if (mono_jit_stats.enabled) {
4861 g_print ("Mono Jit statistics\n");
4862 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4863 mono_jit_stats.max_ratio_method);
4864 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4865 mono_jit_stats.biggest_method);
4867 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4868 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4869 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4870 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4871 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4872 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4873 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4874 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4876 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4877 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4878 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4880 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4881 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4882 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4883 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4885 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4886 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4887 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4888 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4889 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4890 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4891 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4892 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4894 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4895 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4896 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4898 g_free (mono_jit_stats.max_ratio_method);
4899 mono_jit_stats.max_ratio_method = NULL;
4900 g_free (mono_jit_stats.biggest_method);
4901 mono_jit_stats.biggest_method = NULL;
4905 void
4906 mini_cleanup (MonoDomain *domain)
4908 if (mono_profiler_sampling_enabled ())
4909 mono_runtime_shutdown_stat_profiler ();
4911 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4913 #ifndef DISABLE_COM
4914 mono_cominterop_release_all_rcws ();
4915 #endif
4917 #ifndef MONO_CROSS_COMPILE
4919 * mono_domain_finalize () needs to be called early since it needs the
4920 * execution engine still fully working (it may invoke managed finalizers).
4922 mono_domain_finalize (domain, 2000);
4923 #endif
4925 /* This accesses metadata so needs to be called before runtime shutdown */
4926 print_jit_stats ();
4928 #ifndef MONO_CROSS_COMPILE
4929 mono_runtime_cleanup (domain);
4930 #endif
4932 mono_threadpool_cleanup ();
4934 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4936 mono_profiler_cleanup ();
4938 if (profile_options)
4939 g_ptr_array_free (profile_options, TRUE);
4941 free_jit_tls_data (mono_tls_get_jit_tls ());
4943 mono_icall_cleanup ();
4945 mono_runtime_cleanup_handlers ();
4947 #ifndef MONO_CROSS_COMPILE
4948 mono_domain_free (domain, TRUE);
4949 #endif
4951 #ifdef ENABLE_LLVM
4952 if (mono_use_llvm)
4953 mono_llvm_cleanup ();
4954 #endif
4956 mono_aot_cleanup ();
4958 mono_trampolines_cleanup ();
4960 mono_unwind_cleanup ();
4962 mono_code_manager_destroy (global_codeman);
4963 g_free (vtable_trampolines);
4965 mini_jit_cleanup ();
4967 mono_tramp_info_cleanup ();
4969 mono_arch_cleanup ();
4971 mono_generic_sharing_cleanup ();
4973 mono_cleanup ();
4975 mono_trace_cleanup ();
4977 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4979 if (mono_inject_async_exc_method)
4980 mono_method_desc_free (mono_inject_async_exc_method);
4982 mono_tls_free_keys ();
4984 mono_os_mutex_destroy (&jit_mutex);
4986 mono_code_manager_cleanup ();
4988 #ifndef HOST_WIN32
4989 mono_w32handle_cleanup ();
4990 #endif
4993 void
4994 mono_set_defaults (int verbose_level, guint32 opts)
4996 mini_verbose = verbose_level;
4997 mono_set_optimizations (opts);
5000 void
5001 mono_disable_optimizations (guint32 opts)
5003 default_opt &= ~opts;
5006 void
5007 mono_set_optimizations (guint32 opts)
5009 default_opt = opts;
5010 default_opt_set = TRUE;
5011 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
5012 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
5013 #else
5014 if (mono_llvm_only)
5015 mono_set_generic_sharing_vt_supported (TRUE);
5016 #endif
5019 void
5020 mono_set_verbose_level (guint32 level)
5022 mini_verbose = level;
5026 * mono_get_runtime_build_info:
5027 * The returned string is owned by the caller. The returned string
5028 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
5029 * \returns the runtime version + build date in string format.
5031 char*
5032 mono_get_runtime_build_info (void)
5034 if (mono_build_date)
5035 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
5036 else
5037 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
5040 static void
5041 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
5043 GHashTable *assemblies = (GHashTable*)user_data;
5044 MonoImage *image = mono_assembly_get_image_internal (ass);
5045 MonoMethod *method, *invoke;
5046 int i, count = 0;
5048 if (g_hash_table_lookup (assemblies, ass))
5049 return;
5051 g_hash_table_insert (assemblies, ass, ass);
5053 if (mini_verbose > 0)
5054 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
5056 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5057 ERROR_DECL (error);
5059 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
5060 if (!method) {
5061 mono_error_cleanup (error); /* FIXME don't swallow the error */
5062 continue;
5064 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
5065 continue;
5066 if (method->is_generic || mono_class_is_gtd (method->klass))
5067 continue;
5069 count++;
5070 if (mini_verbose > 1) {
5071 char * desc = mono_method_full_name (method, TRUE);
5072 g_print ("Compiling %d %s\n", count, desc);
5073 g_free (desc);
5075 mono_compile_method_checked (method, error);
5076 if (!is_ok (error)) {
5077 mono_error_cleanup (error); /* FIXME don't swallow the error */
5078 continue;
5080 if (strcmp (method->name, "Finalize") == 0) {
5081 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
5082 mono_compile_method_checked (invoke, error);
5083 mono_error_assert_ok (error);
5085 #ifndef DISABLE_REMOTING
5086 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
5087 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
5088 mono_error_assert_ok (error);
5089 mono_compile_method_checked (invoke, error);
5090 mono_error_assert_ok (error);
5092 #endif
5095 /* Load and precompile referenced assemblies as well */
5096 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
5097 mono_assembly_load_reference (image, i);
5098 if (image->references [i])
5099 mono_precompile_assembly (image->references [i], assemblies);
5103 void mono_precompile_assemblies ()
5105 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
5107 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
5109 g_hash_table_destroy (assemblies);
5113 * Used by LLVM.
5114 * Have to export this for AOT.
5116 void
5117 mono_personality (void)
5119 /* Not used */
5120 g_assert_not_reached ();
5124 static MonoBreakPolicy
5125 always_insert_breakpoint (MonoMethod *method)
5127 return MONO_BREAK_POLICY_ALWAYS;
5130 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5133 * mono_set_break_policy:
5134 * \param policy_callback the new callback function
5136 * Allow embedders to decide whether to actually obey breakpoint instructions
5137 * (both break IL instructions and \c Debugger.Break method calls), for example
5138 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5139 * untrusted or semi-trusted code.
5141 * \p policy_callback will be called every time a break point instruction needs to
5142 * be inserted with the method argument being the method that calls \c Debugger.Break
5143 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5144 * if it wants the breakpoint to not be effective in the given method.
5145 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5147 void
5148 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5150 if (policy_callback)
5151 break_policy_func = policy_callback;
5152 else
5153 break_policy_func = always_insert_breakpoint;
5156 gboolean
5157 mini_should_insert_breakpoint (MonoMethod *method)
5159 switch (break_policy_func (method)) {
5160 case MONO_BREAK_POLICY_ALWAYS:
5161 return TRUE;
5162 case MONO_BREAK_POLICY_NEVER:
5163 return FALSE;
5164 case MONO_BREAK_POLICY_ON_DBG:
5165 g_warning ("mdb no longer supported");
5166 return FALSE;
5167 default:
5168 g_warning ("Incorrect value returned from break policy callback");
5169 return FALSE;
5173 // Custom handlers currently only implemented by Windows.
5174 #ifndef HOST_WIN32
5175 gboolean
5176 mono_runtime_install_custom_handlers (const char *handlers)
5178 return FALSE;
5181 void
5182 mono_runtime_install_custom_handlers_usage (void)
5184 fprintf (stdout,
5185 "Custom Handlers:\n"
5186 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5187 " separated list of available handlers to install.\n"
5188 "\n"
5189 "No handlers supported on current platform.\n");
5191 #endif /* HOST_WIN32 */