Small step toward reduction/elimination of JIT icall hashing. (#14149)
[mono-project.git] / mono / mini / mini-runtime.c
blob3a815278345492364a37f5d6fb5ab5e67b232dfb
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 #include <mono/metadata/loader-internals.h>
56 #define MONO_MATH_DECLARE_ALL 1
57 #include <mono/utils/mono-math.h>
58 #include <mono/utils/mono-compiler.h>
59 #include <mono/utils/mono-counters.h>
60 #include <mono/utils/mono-error-internals.h>
61 #include <mono/utils/mono-logger-internals.h>
62 #include <mono/utils/mono-mmap.h>
63 #include <mono/utils/mono-path.h>
64 #include <mono/utils/mono-tls.h>
65 #include <mono/utils/mono-hwcap.h>
66 #include <mono/utils/dtrace.h>
67 #include <mono/utils/mono-signal-handler.h>
68 #include <mono/utils/mono-threads.h>
69 #include <mono/utils/mono-threads-coop.h>
70 #include <mono/utils/checked-build.h>
71 #include <mono/utils/mono-compiler.h>
72 #include <mono/utils/mono-proclib.h>
73 #include <mono/metadata/w32handle.h>
74 #include <mono/metadata/threadpool.h>
76 #include "mini.h"
77 #include "seq-points.h"
78 #include "tasklets.h"
79 #include <string.h>
80 #include <ctype.h>
81 #include "trace.h"
82 #include "version.h"
83 #include "aot-compiler.h"
84 #include "aot-runtime.h"
85 #include "llvmonly-runtime.h"
87 #include "jit-icalls.h"
89 #include "mini-gc.h"
90 #include "mini-llvm.h"
91 #include "debugger-agent.h"
92 #include "lldb.h"
93 #include "mini-runtime.h"
94 #include "interp/interp.h"
96 #ifdef MONO_ARCH_LLVM_SUPPORTED
97 #ifdef ENABLE_LLVM
98 #include "mini-llvm-cpp.h"
99 #include "llvm-jit.h"
100 #endif
101 #endif
102 #include "mono/metadata/icall-signatures.h"
104 static guint32 default_opt = 0;
105 static gboolean default_opt_set = FALSE;
107 gboolean mono_compile_aot = FALSE;
108 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
109 gboolean mono_aot_only = FALSE;
110 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
111 gboolean mono_llvm_only = FALSE;
112 /* By default, don't require AOT but attempt to probe */
113 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NORMAL;
114 MonoEEFeatures mono_ee_features;
116 const char *mono_build_date;
117 gboolean mono_do_signal_chaining;
118 gboolean mono_do_crash_chaining;
119 int mini_verbose = 0;
122 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
123 * it can load AOT code compiled by LLVM.
125 gboolean mono_use_llvm = FALSE;
127 gboolean mono_use_interpreter = FALSE;
128 const char *mono_interp_opts_string = NULL;
130 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
131 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
132 static mono_mutex_t jit_mutex;
134 static MonoCodeManager *global_codeman;
136 MonoDebugOptions mini_debug_options;
137 char *sdb_options;
139 #ifdef VALGRIND_JIT_REGISTER_MAP
140 int valgrind_register;
141 #endif
142 GList* mono_aot_paths;
144 static GPtrArray *profile_options;
146 static GSList *tramp_infos;
147 GSList *mono_interp_only_classes;
149 static void register_icalls (void);
151 gboolean
152 mono_running_on_valgrind (void)
154 #ifndef HOST_WIN32
155 if (RUNNING_ON_VALGRIND){
156 #ifdef VALGRIND_JIT_REGISTER_MAP
157 valgrind_register = TRUE;
158 #endif
159 return TRUE;
160 } else
161 #endif
162 return FALSE;
165 typedef struct {
166 void *ip;
167 MonoMethod *method;
168 } FindTrampUserData;
170 static void
171 find_tramp (gpointer key, gpointer value, gpointer user_data)
173 FindTrampUserData *ud = (FindTrampUserData*)user_data;
175 if (value == ud->ip)
176 ud->method = (MonoMethod*)key;
179 /* debug function */
180 char*
181 mono_get_method_from_ip (void *ip)
183 MonoJitInfo *ji;
184 MonoMethod *method;
185 char *method_name;
186 char *res;
187 MonoDomain *domain = mono_domain_get ();
188 MonoDebugSourceLocation *location;
189 FindTrampUserData user_data;
191 if (!domain)
192 domain = mono_get_root_domain ();
194 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
195 if (!ji) {
196 user_data.ip = ip;
197 user_data.method = NULL;
198 mono_domain_lock (domain);
199 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
200 mono_domain_unlock (domain);
201 if (user_data.method) {
202 char *mname = mono_method_full_name (user_data.method, TRUE);
203 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
204 g_free (mname);
205 return res;
207 else
208 return NULL;
209 } else if (ji->is_trampoline) {
210 res = g_strdup_printf ("<%p - %s trampoline>", ip, ji->d.tramp_info->name);
211 return res;
214 method = jinfo_get_method (ji);
215 method_name = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_IL);
216 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
218 char *file_loc = NULL;
219 if (location)
220 file_loc = g_strdup_printf ("[%s :: %du]", location->source_file, location->row);
222 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);
224 mono_debug_free_source_location (location);
225 g_free (method_name);
226 g_free (file_loc);
228 return res;
232 * mono_pmip:
233 * \param ip an instruction pointer address
235 * This method is used from a debugger to get the name of the
236 * method at address \p ip. This routine is typically invoked from
237 * a debugger like this:
239 * (gdb) print mono_pmip ($pc)
241 * \returns the name of the method at address \p ip.
243 G_GNUC_UNUSED char *
244 mono_pmip (void *ip)
246 return mono_get_method_from_ip (ip);
250 * mono_print_method_from_ip:
251 * \param ip an instruction pointer address
253 * This method is used from a debugger to get the name of the
254 * method at address \p ip.
256 * This prints the name of the method at address \p ip in the standard
257 * output. Unlike \c mono_pmip which returns a string, this routine
258 * prints the value on the standard output.
260 MONO_ATTR_USED void
261 mono_print_method_from_ip (void *ip)
263 MonoJitInfo *ji;
264 char *method;
265 MonoDebugSourceLocation *source;
266 MonoDomain *domain = mono_domain_get ();
267 MonoDomain *target_domain = mono_domain_get ();
268 FindTrampUserData user_data;
269 MonoGenericSharingContext*gsctx;
270 const char *shared_type;
272 if (!domain)
273 domain = mono_get_root_domain ();
274 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
275 if (ji && ji->is_trampoline) {
276 MonoTrampInfo *tinfo = ji->d.tramp_info;
278 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
279 return;
282 if (!ji) {
283 user_data.ip = ip;
284 user_data.method = NULL;
285 mono_domain_lock (domain);
286 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
287 mono_domain_unlock (domain);
289 if (user_data.method) {
290 char *mname = mono_method_full_name (user_data.method, TRUE);
291 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
292 g_free (mname);
293 return;
296 g_print ("No method at %p\n", ip);
297 fflush (stdout);
298 return;
300 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
301 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
303 gsctx = mono_jit_info_get_generic_sharing_context (ji);
304 shared_type = "";
305 if (gsctx) {
306 if (gsctx->is_gsharedvt)
307 shared_type = "gsharedvt ";
308 else
309 shared_type = "gshared ";
312 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);
314 if (source)
315 g_print ("%s:%d\n", source->source_file, source->row);
316 fflush (stdout);
318 mono_debug_free_source_location (source);
319 g_free (method);
323 * mono_method_same_domain:
325 * Determine whenever two compiled methods are in the same domain, thus
326 * the address of the callee can be embedded in the caller.
328 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
330 MonoMethod *cmethod;
332 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
333 return FALSE;
336 * If the call was made from domain-neutral to domain-specific
337 * code, we can't patch the call site.
339 if (caller->domain_neutral && !callee->domain_neutral)
340 return FALSE;
342 cmethod = jinfo_get_method (caller);
343 if ((cmethod->klass == mono_defaults.appdomain_class) &&
344 (strstr (cmethod->name, "InvokeInDomain"))) {
345 /* The InvokeInDomain methods change the current appdomain */
346 return FALSE;
349 return TRUE;
353 * mono_global_codeman_reserve:
355 * Allocate code memory from the global code manager.
357 void *(mono_global_codeman_reserve) (int size)
359 void *ptr;
361 if (mono_aot_only)
362 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
364 if (!global_codeman) {
365 /* This can happen during startup */
366 global_codeman = mono_code_manager_new ();
367 return mono_code_manager_reserve (global_codeman, size);
369 else {
370 mono_jit_lock ();
371 ptr = mono_code_manager_reserve (global_codeman, size);
372 mono_jit_unlock ();
373 return ptr;
377 /* The callback shouldn't take any locks */
378 void
379 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
381 mono_jit_lock ();
382 mono_code_manager_foreach (global_codeman, func, user_data);
383 mono_jit_unlock ();
387 * mono_create_unwind_op:
389 * Create an unwind op with the given parameters.
391 MonoUnwindOp*
392 mono_create_unwind_op (int when, int tag, int reg, int val)
394 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
396 op->op = tag;
397 op->reg = reg;
398 op->val = val;
399 op->when = when;
401 return op;
404 MonoJumpInfoToken *
405 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
407 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
408 res->image = image;
409 res->token = token;
410 res->has_context = context != NULL;
411 if (context)
412 memcpy (&res->context, context, sizeof (MonoGenericContext));
414 return res;
417 MonoJumpInfoToken *
418 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
420 return mono_jump_info_token_new2 (mp, image, token, NULL);
424 * mono_tramp_info_create:
426 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
427 * of JI, and UNWIND_OPS.
429 MonoTrampInfo*
430 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
432 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
434 info->name = g_strdup (name);
435 info->code = code;
436 info->code_size = code_size;
437 info->ji = ji;
438 info->unwind_ops = unwind_ops;
440 return info;
443 void
444 mono_tramp_info_free (MonoTrampInfo *info)
446 g_free (info->name);
448 // FIXME: ji
449 mono_free_unwind_info (info->unwind_ops);
450 if (info->owns_uw_info)
451 g_free (info->uw_info);
452 g_free (info);
455 static void
456 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
458 MonoJitInfo *ji;
460 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
461 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
462 ji->d.tramp_info = info;
463 ji->is_trampoline = TRUE;
465 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
467 mono_jit_info_table_add (domain, ji);
471 * mono_tramp_info_register:
473 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
474 * INFO can be NULL.
475 * Frees INFO.
477 static void
478 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
480 MonoTrampInfo *copy;
482 if (!info)
483 return;
485 if (!domain)
486 domain = mono_get_root_domain ();
488 if (domain)
489 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
490 else
491 copy = g_new0 (MonoTrampInfo, 1);
493 copy->code = info->code;
494 copy->code_size = info->code_size;
495 copy->name = g_strdup (info->name);
497 if (info->unwind_ops) {
498 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
499 copy->owns_uw_info = TRUE;
500 if (domain) {
501 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
502 guint8 *temp = copy->uw_info;
503 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
504 memcpy (copy->uw_info, temp, copy->uw_info_len);
505 g_free (temp);
507 } else {
508 /* Trampolines from aot have the unwind ops already encoded */
509 copy->uw_info = info->uw_info;
510 copy->uw_info_len = info->uw_info_len;
513 mono_save_trampoline_xdebug_info (info);
514 mono_lldb_save_trampoline_info (info);
516 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
517 if (!aot)
518 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
519 #endif
521 if (!domain) {
522 /* If no root domain has been created yet, postpone the registration. */
523 mono_jit_lock ();
524 tramp_infos = g_slist_prepend (tramp_infos, copy);
525 mono_jit_unlock ();
526 } else if (copy->uw_info) {
527 /* Only register trampolines that have unwind infos */
528 register_trampoline_jit_info (domain, copy);
531 if (mono_jit_map_is_enabled ())
532 mono_emit_jit_tramp (info->code, info->code_size, info->name);
534 mono_tramp_info_free (info);
537 void
538 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
540 mono_tramp_info_register_internal (info, domain, FALSE);
543 void
544 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
546 mono_tramp_info_register_internal (info, domain, TRUE);
549 static void
550 mono_tramp_info_cleanup (void)
552 GSList *l;
554 for (l = tramp_infos; l; l = l->next) {
555 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
557 mono_tramp_info_free (info);
559 g_slist_free (tramp_infos);
562 /* Register trampolines created before the root domain was created in the jit info tables */
563 static void
564 register_trampolines (MonoDomain *domain)
566 GSList *l;
568 for (l = tramp_infos; l; l = l->next) {
569 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
571 register_trampoline_jit_info (domain, info);
575 G_GNUC_UNUSED static void
576 break_count (void)
581 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
582 * Set a breakpoint in break_count () to break the last time <x> is done.
584 G_GNUC_UNUSED gboolean
585 mono_debug_count (void)
587 static int count = 0, int_val = 0;
588 static gboolean inited, has_value = FALSE;
590 count ++;
592 if (!inited) {
593 char *value = g_getenv ("COUNT");
594 if (value) {
595 int_val = atoi (value);
596 g_free (value);
597 has_value = TRUE;
599 inited = TRUE;
602 if (!has_value)
603 return TRUE;
605 if (count == int_val)
606 break_count ();
608 if (count > int_val)
609 return FALSE;
611 return TRUE;
614 MonoMethod*
615 mono_icall_get_wrapper_method (MonoJitICallInfo* callinfo)
617 gboolean check_exc = TRUE;
619 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
620 /* This icall is used to check for exceptions, so don't check in the wrapper */
621 check_exc = FALSE;
623 return mono_marshal_get_icall_wrapper (callinfo, check_exc);
626 gconstpointer
627 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
629 ERROR_DECL (error);
630 MonoMethod *wrapper;
631 gconstpointer trampoline;
632 MonoDomain *domain = mono_get_root_domain ();
634 if (callinfo->wrapper)
635 return callinfo->wrapper;
637 if (callinfo->trampoline)
638 return callinfo->trampoline;
640 wrapper = mono_icall_get_wrapper_method (callinfo);
642 if (do_compile) {
643 trampoline = mono_compile_method_checked (wrapper, error);
644 mono_error_assert_ok (error);
645 } else {
646 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
647 mono_error_assert_ok (error);
648 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
651 mono_loader_lock ();
652 if (!callinfo->trampoline) {
653 mono_register_jit_icall_wrapper (callinfo, trampoline);
654 callinfo->trampoline = trampoline;
656 mono_loader_unlock ();
658 return callinfo->trampoline;
661 gconstpointer
662 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
664 return mono_icall_get_wrapper_full (callinfo, FALSE);
667 static MonoJitDynamicMethodInfo*
668 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
670 MonoJitDynamicMethodInfo *res;
672 if (domain_jit_info (domain)->dynamic_code_hash)
673 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
674 else
675 res = NULL;
676 return res;
679 #ifdef __cplusplus
680 template <typename T>
681 static void
682 register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, T func, const char *symbol, gboolean no_wrapper)
683 #else
684 static void
685 register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, const char *symbol, gboolean no_wrapper)
686 #endif
688 #ifndef DISABLE_JIT
689 mini_register_opcode_emulation (opcode, name, sig, func, symbol, no_wrapper);
690 #else
691 g_assert (!sig->hasthis);
692 g_assert (sig->param_count < 3);
694 mono_register_jit_icall_full (func, name, sig, no_wrapper, symbol);
695 #endif
698 // This layering is only meant to provide smaller easier to read temporary change.
699 // The de-stringing of name in the caller will be useful later.
700 #define register_opcode_emulation(opcode, name, sig, func, symbol, no_wrapper) \
701 register_opcode_emulation (opcode, #name, sig, func, symbol, no_wrapper)
704 * For JIT icalls implemented in C.
705 * NAME should be the same as the name of the C function whose address is FUNC.
706 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
707 * can't throw exceptions.
709 #ifdef __cplusplus
710 template <typename T>
711 static void
712 register_icall (T func, const char *name, MonoMethodSignature *sig, gboolean avoid_wrapper)
713 #else
714 static void
715 register_icall (gpointer func, const char *name, MonoMethodSignature *sig, gboolean avoid_wrapper)
716 #endif
718 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, name);
721 #ifdef __cplusplus
722 template <typename T>
723 static void
724 register_icall_no_wrapper (T func, const char *name, MonoMethodSignature *sig)
725 #else
726 static void
727 register_icall_no_wrapper (gpointer func, const char *name, MonoMethodSignature *sig)
728 #endif
730 mono_register_jit_icall_full (func, name, sig, TRUE, name);
733 #ifdef __cplusplus
734 template <typename T>
735 static void
736 register_icall_with_wrapper (T func, const char *name, MonoMethodSignature *sig)
737 #else
738 static void
739 register_icall_with_wrapper (gpointer func, const char *name, MonoMethodSignature *sig)
740 #endif
742 mono_register_jit_icall_full (func, name, sig, FALSE, name);
746 * Register an icall where FUNC is dynamically generated or otherwise not
747 * possible to link to it using NAME during AOT.
749 #ifdef __cplusplus
750 template <typename T>
751 static void
752 register_dyn_icall (T func, const char *name, MonoMethodSignature *sig, gboolean save)
753 #else
754 static void
755 register_dyn_icall (gpointer func, const char *name, MonoMethodSignature *sig, gboolean save)
756 #endif
758 mono_register_jit_icall (func, name, sig, save);
761 MonoLMF *
762 mono_get_lmf (void)
764 MonoJitTlsData *jit_tls;
766 if ((jit_tls = mono_tls_get_jit_tls ()))
767 return jit_tls->lmf;
769 * We do not assert here because this function can be called from
770 * mini-gc.c on a thread that has not executed any managed code, yet
771 * (the thread object allocation can trigger a collection).
773 return NULL;
776 void
777 mono_set_lmf (MonoLMF *lmf)
779 (*mono_get_lmf_addr ()) = lmf;
782 static void
783 mono_set_jit_tls (MonoJitTlsData *jit_tls)
785 MonoThreadInfo *info;
787 mono_tls_set_jit_tls (jit_tls);
789 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
790 info = mono_thread_info_current ();
791 if (info)
792 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
795 static void
796 mono_set_lmf_addr (MonoLMF **lmf_addr)
798 MonoThreadInfo *info;
800 mono_tls_set_lmf_addr (lmf_addr);
802 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
803 info = mono_thread_info_current ();
804 if (info)
805 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
809 * mono_push_lmf:
811 * Push an MonoLMFExt frame on the LMF stack.
813 void
814 mono_push_lmf (MonoLMFExt *ext)
816 MonoLMF **lmf_addr;
818 lmf_addr = mono_get_lmf_addr ();
820 ext->lmf.previous_lmf = *lmf_addr;
821 /* Mark that this is a MonoLMFExt */
822 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
824 mono_set_lmf ((MonoLMF*)ext);
828 * mono_pop_lmf:
830 * Pop the last frame from the LMF stack.
832 void
833 mono_pop_lmf (MonoLMF *lmf)
835 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
839 * mono_jit_thread_attach:
841 * Called by Xamarin.Mac and other products. Attach thread to runtime if
842 * needed and switch to @domain.
844 * This function is external only and @deprecated don't use it. Use mono_threads_attach_coop ().
846 * If the thread is newly-attached, put into GC Safe mode.
848 * @return the original domain which needs to be restored, or NULL.
850 MonoDomain*
851 mono_jit_thread_attach (MonoDomain *domain)
853 MonoDomain *orig;
854 gboolean attached;
856 if (!domain) {
857 /* Happens when called from AOTed code which is only used in the root domain. */
858 domain = mono_get_root_domain ();
861 g_assert (domain);
863 attached = mono_tls_get_jit_tls () != NULL;
865 if (!attached) {
866 mono_thread_attach (domain);
868 // #678164
869 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
871 /* mono_jit_thread_attach is external-only and not called by
872 * the runtime on any of our own threads. So if we get here,
873 * the thread is running native code - leave it in GC Safe mode
874 * and leave it to the n2m invoke wrappers or MONO_API entry
875 * points to switch to GC Unsafe.
877 MONO_STACKDATA (stackdata);
878 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackdata);
881 orig = mono_domain_get ();
882 if (orig != domain)
883 mono_domain_set (domain, TRUE);
885 return orig != domain ? orig : NULL;
889 * mono_jit_set_domain:
891 * Set domain to @domain if @domain is not null
893 void
894 mono_jit_set_domain (MonoDomain *domain)
896 g_assert (!mono_threads_is_blocking_transition_enabled ());
898 if (domain)
899 mono_domain_set (domain, TRUE);
903 * mono_thread_abort:
904 * \param obj exception object
905 * Abort the thread, print exception information and stack trace
907 static void
908 mono_thread_abort (MonoObject *obj)
910 /* MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); */
912 /* handle_remove should be eventually called for this thread, too
913 g_free (jit_tls);*/
915 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
916 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
917 ((obj->vtable->klass) == mono_class_try_get_appdomain_unloaded_exception_class () &&
918 mono_thread_info_current ()->runtime_thread)) {
919 mono_thread_exit ();
920 } else {
921 mono_invoke_unhandled_exception_hook (obj);
925 static MonoJitTlsData*
926 setup_jit_tls_data (gpointer stack_start, MonoAbortFunction abort_func)
928 MonoJitTlsData *jit_tls;
929 MonoLMF *lmf;
931 jit_tls = mono_tls_get_jit_tls ();
932 if (jit_tls)
933 return jit_tls;
935 jit_tls = g_new0 (MonoJitTlsData, 1);
937 jit_tls->abort_func = abort_func;
938 jit_tls->end_of_stack = stack_start;
940 mono_set_jit_tls (jit_tls);
942 lmf = g_new0 (MonoLMF, 1);
943 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
945 jit_tls->first_lmf = lmf;
947 mono_set_lmf_addr (&jit_tls->lmf);
949 jit_tls->lmf = lmf;
951 #ifdef MONO_ARCH_HAVE_TLS_INIT
952 mono_arch_tls_init ();
953 #endif
955 mono_setup_altstack (jit_tls);
957 return jit_tls;
960 static void
961 free_jit_tls_data (MonoJitTlsData *jit_tls)
963 //This happens during AOT cuz the thread is never attached
964 if (!jit_tls)
965 return;
966 mono_arch_free_jit_tls_data (jit_tls);
967 mono_free_altstack (jit_tls);
969 g_free (jit_tls->first_lmf);
970 g_free (jit_tls->interp_context);
971 g_free (jit_tls);
974 static void
975 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
977 MonoThreadInfo *thread;
978 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
979 thread = mono_thread_info_current_unchecked ();
980 if (thread)
981 thread->jit_data = jit_tls;
983 mono_arch_cpu_init ();
986 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
988 static void
989 mono_thread_abort_dummy (MonoObject *obj)
991 if (mono_thread_attach_aborted_cb)
992 mono_thread_attach_aborted_cb (obj);
993 else
994 mono_thread_abort (obj);
997 static void
998 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
1000 MonoThreadInfo *thread;
1001 MonoJitTlsData *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
1002 thread = mono_thread_info_current_unchecked ();
1003 if (thread)
1004 thread->jit_data = jit_tls;
1006 mono_arch_cpu_init ();
1009 static void
1010 mini_thread_cleanup (MonoNativeThreadId tid)
1012 MonoJitTlsData *jit_tls = NULL;
1013 MonoThreadInfo *info;
1015 info = mono_thread_info_current_unchecked ();
1017 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
1018 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
1019 * not a trivial thing.
1021 * The current offender is mono_thread_manage which cleanup threads from the outside.
1023 if (info && mono_thread_info_get_tid (info) == tid) {
1024 jit_tls = info->jit_data;
1025 info->jit_data = NULL;
1027 mono_set_jit_tls (NULL);
1029 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1030 if (mono_get_lmf ()) {
1031 mono_set_lmf (NULL);
1032 mono_set_lmf_addr (NULL);
1034 } else {
1035 info = mono_thread_info_lookup (tid);
1036 if (info) {
1037 jit_tls = info->jit_data;
1038 info->jit_data = NULL;
1040 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1043 if (jit_tls)
1044 free_jit_tls_data (jit_tls);
1047 MonoJumpInfo *
1048 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1050 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1052 ji->ip.i = ip;
1053 ji->type = type;
1054 ji->data.target = target;
1055 ji->next = list;
1057 return ji;
1060 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1062 static const char* const patch_info_str[] = {
1063 #define PATCH_INFO(a,b) "" #a,
1064 #include "patch-info.h"
1065 #undef PATCH_INFO
1068 const char*
1069 mono_ji_type_to_string (MonoJumpInfoType type)
1071 return patch_info_str [type];
1074 void
1075 mono_print_ji (const MonoJumpInfo *ji)
1077 const char *type = patch_info_str [ji->type];
1078 switch (ji->type) {
1079 case MONO_PATCH_INFO_RGCTX_FETCH:
1080 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1081 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1083 printf ("[%s ", type);
1084 mono_print_ji (entry->data);
1085 printf (" -> %s]", mono_rgctx_info_type_to_str (entry->info_type));
1086 break;
1088 case MONO_PATCH_INFO_METHOD:
1089 case MONO_PATCH_INFO_METHODCONST:
1090 case MONO_PATCH_INFO_METHOD_FTNDESC: {
1091 char *s = mono_method_get_full_name (ji->data.method);
1092 printf ("[%s %s]", type, s);
1093 g_free (s);
1094 break;
1096 case MONO_PATCH_INFO_JIT_ICALL: {
1097 printf ("[JIT_ICALL %s]", ji->data.name);
1098 break;
1100 case MONO_PATCH_INFO_CLASS:
1101 case MONO_PATCH_INFO_VTABLE: {
1102 char *name = mono_class_full_name (ji->data.klass);
1103 printf ("[%s %s]", type, name);
1104 g_free (name);
1105 break;
1107 default:
1108 printf ("[%s]", type);
1109 break;
1113 #else
1115 const char*
1116 mono_ji_type_to_string (MonoJumpInfoType type)
1118 return "";
1121 void
1122 mono_print_ji (const MonoJumpInfo *ji)
1126 #endif
1129 * mono_patch_info_dup_mp:
1131 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1133 MonoJumpInfo*
1134 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1136 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1137 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1139 switch (patch_info->type) {
1140 case MONO_PATCH_INFO_RVA:
1141 case MONO_PATCH_INFO_LDSTR:
1142 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1143 case MONO_PATCH_INFO_LDTOKEN:
1144 case MONO_PATCH_INFO_DECLSEC:
1145 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1146 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1147 break;
1148 case MONO_PATCH_INFO_SWITCH:
1149 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1150 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1151 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1152 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1153 break;
1154 case MONO_PATCH_INFO_RGCTX_FETCH:
1155 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1156 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1157 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1158 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1159 break;
1160 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1161 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1162 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1163 break;
1164 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1165 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1166 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1167 break;
1168 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1169 MonoGSharedVtMethodInfo *info;
1170 MonoGSharedVtMethodInfo *oinfo;
1171 int i;
1173 oinfo = patch_info->data.gsharedvt_method;
1174 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1175 res->data.gsharedvt_method = info;
1176 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1177 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1178 for (i = 0; i < oinfo->num_entries; ++i) {
1179 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1180 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1182 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1184 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1185 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1186 break;
1188 case MONO_PATCH_INFO_VIRT_METHOD: {
1189 MonoJumpInfoVirtMethod *info;
1190 MonoJumpInfoVirtMethod *oinfo;
1192 oinfo = patch_info->data.virt_method;
1193 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1194 res->data.virt_method = info;
1195 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1196 break;
1198 default:
1199 break;
1202 return res;
1205 guint
1206 mono_patch_info_hash (gconstpointer data)
1208 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1210 switch (ji->type) {
1211 case MONO_PATCH_INFO_RVA:
1212 case MONO_PATCH_INFO_LDSTR:
1213 case MONO_PATCH_INFO_LDTOKEN:
1214 case MONO_PATCH_INFO_DECLSEC:
1215 return (ji->type << 8) | ji->data.token->token;
1216 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1217 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1218 case MONO_PATCH_INFO_JIT_ICALL:
1219 return (ji->type << 8) | g_str_hash (ji->data.name);
1220 case MONO_PATCH_INFO_VTABLE:
1221 case MONO_PATCH_INFO_CLASS:
1222 case MONO_PATCH_INFO_IID:
1223 case MONO_PATCH_INFO_ADJUSTED_IID:
1224 case MONO_PATCH_INFO_METHODCONST:
1225 case MONO_PATCH_INFO_METHOD:
1226 case MONO_PATCH_INFO_METHOD_JUMP:
1227 case MONO_PATCH_INFO_METHOD_FTNDESC:
1228 case MONO_PATCH_INFO_IMAGE:
1229 case MONO_PATCH_INFO_ICALL_ADDR:
1230 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1231 case MONO_PATCH_INFO_FIELD:
1232 case MONO_PATCH_INFO_SFLDA:
1233 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1234 case MONO_PATCH_INFO_METHOD_RGCTX:
1235 case MONO_PATCH_INFO_SIGNATURE:
1236 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1237 case MONO_PATCH_INFO_AOT_JIT_INFO:
1238 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1239 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1240 return (ji->type << 8) | (gssize)ji->data.target;
1241 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1242 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1243 case MONO_PATCH_INFO_RGCTX_FETCH:
1244 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1245 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1247 if (e->in_mrgctx)
1248 return (ji->type << 8) | (gssize)e->d.method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1249 else
1250 return (ji->type << 8) | (gssize)e->d.klass | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1252 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1253 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1254 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1255 case MONO_PATCH_INFO_GC_NURSERY_START:
1256 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1257 case MONO_PATCH_INFO_GOT_OFFSET:
1258 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1259 case MONO_PATCH_INFO_AOT_MODULE:
1260 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1261 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1262 return (ji->type << 8);
1263 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1264 return (ji->type << 8) | (ji->data.uindex);
1265 case MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR:
1266 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1267 return (ji->type << 8) | (ji->data.index);
1268 case MONO_PATCH_INFO_SWITCH:
1269 return (ji->type << 8) | ji->data.table->table_size;
1270 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1271 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1272 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1273 /* Hash on the selector name */
1274 return g_str_hash (ji->data.target);
1275 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1276 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1277 case MONO_PATCH_INFO_LDSTR_LIT:
1278 return g_str_hash (ji->data.target);
1279 case MONO_PATCH_INFO_VIRT_METHOD: {
1280 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1282 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1284 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1285 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1286 return (ji->type << 8) | g_str_hash (ji->data.target);
1287 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1288 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1289 default:
1290 printf ("info type: %d\n", ji->type);
1291 mono_print_ji (ji); printf ("\n");
1292 g_assert_not_reached ();
1293 return 0;
1298 * mono_patch_info_equal:
1300 * This might fail to recognize equivalent patches, i.e. floats, so its only
1301 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1302 * in AOT.
1304 gint
1305 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1307 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1308 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1310 if (ji1->type != ji2->type)
1311 return 0;
1313 switch (ji1->type) {
1314 case MONO_PATCH_INFO_RVA:
1315 case MONO_PATCH_INFO_LDSTR:
1316 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1317 case MONO_PATCH_INFO_LDTOKEN:
1318 case MONO_PATCH_INFO_DECLSEC:
1319 if ((ji1->data.token->image != ji2->data.token->image) ||
1320 (ji1->data.token->token != ji2->data.token->token) ||
1321 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1322 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1323 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1324 return 0;
1325 break;
1326 case MONO_PATCH_INFO_JIT_ICALL:
1327 return g_str_equal (ji1->data.name, ji2->data.name);
1328 case MONO_PATCH_INFO_RGCTX_FETCH:
1329 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1330 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1331 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1333 return e1->d.method == e2->d.method && e1->d.klass == e2->d.klass && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
1335 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1336 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1337 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1339 return c1->sig == c2->sig && c1->method == c2->method;
1341 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1342 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1343 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1344 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;
1345 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
1346 return ji1->data.uindex == ji2->data.uindex;
1347 case MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR:
1348 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1349 return ji1->data.index == ji2->data.index;
1350 case MONO_PATCH_INFO_VIRT_METHOD:
1351 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1352 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1353 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1354 if (ji1->data.target == ji2->data.target)
1355 return 1;
1356 return strcmp ((const char*)ji1->data.target, (const char*)ji2->data.target) == 0 ? 1 : 0;
1357 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1358 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1359 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1360 return 1;
1361 default:
1362 if (ji1->data.target != ji2->data.target)
1363 return 0;
1364 break;
1367 return 1;
1370 gpointer
1371 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1373 unsigned char *ip = patch_info->ip.i + code;
1374 gconstpointer target = NULL;
1376 error_init (error);
1378 switch (patch_info->type) {
1379 case MONO_PATCH_INFO_BB:
1381 * FIXME: This could be hit for methods without a prolog. Should use -1
1382 * but too much code depends on a 0 initial value.
1384 //g_assert (patch_info->data.bb->native_offset);
1385 target = patch_info->data.bb->native_offset + code;
1386 break;
1387 case MONO_PATCH_INFO_ABS:
1388 target = patch_info->data.target;
1389 break;
1390 case MONO_PATCH_INFO_LABEL:
1391 target = patch_info->data.inst->inst_c0 + code;
1392 break;
1393 case MONO_PATCH_INFO_IP:
1394 target = ip;
1395 break;
1396 case MONO_PATCH_INFO_METHOD_REL:
1397 target = code + patch_info->data.offset;
1398 break;
1399 case MONO_PATCH_INFO_JIT_ICALL: {
1400 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1401 g_assertf (mi, "unknown MONO_PATCH_INFO_JIT_ICALL %s", patch_info->data.name);
1402 target = mono_icall_get_wrapper (mi);
1403 break;
1405 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1406 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1407 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1408 g_assertf (mi, "unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
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_FTNDESC: {
1429 * Return an ftndesc for either AOTed code, or for an interp entry.
1431 target = mini_llvmonly_load_method_ftndesc (patch_info->data.method, FALSE, FALSE, error);
1432 return_val_if_nok (error, NULL);
1433 break;
1435 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1436 gpointer code_slot;
1438 mono_domain_lock (domain);
1439 if (!domain_jit_info (domain)->method_code_hash)
1440 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1441 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1442 if (!code_slot) {
1443 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1444 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1446 mono_domain_unlock (domain);
1447 target = code_slot;
1448 break;
1450 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1451 target = (gpointer)&mono_polling_required;
1452 break;
1453 case MONO_PATCH_INFO_SWITCH: {
1454 gpointer *jump_table;
1455 int i;
1456 if (method && method->dynamic) {
1457 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1458 } else {
1459 if (mono_aot_only) {
1460 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1461 } else {
1462 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1466 for (i = 0; i < patch_info->data.table->table_size; i++) {
1467 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1470 target = jump_table;
1471 break;
1473 case MONO_PATCH_INFO_METHODCONST:
1474 case MONO_PATCH_INFO_CLASS:
1475 case MONO_PATCH_INFO_IMAGE:
1476 case MONO_PATCH_INFO_FIELD:
1477 case MONO_PATCH_INFO_SIGNATURE:
1478 case MONO_PATCH_INFO_AOT_MODULE:
1479 target = patch_info->data.target;
1480 break;
1481 case MONO_PATCH_INFO_IID:
1482 mono_class_init_internal (patch_info->data.klass);
1483 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1484 break;
1485 case MONO_PATCH_INFO_ADJUSTED_IID:
1486 mono_class_init_internal (patch_info->data.klass);
1487 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * TARGET_SIZEOF_VOID_P)));
1488 break;
1489 case MONO_PATCH_INFO_VTABLE:
1490 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1491 mono_error_assert_ok (error);
1492 break;
1493 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1494 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1496 if (del_tramp->is_virtual)
1497 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1498 else
1499 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1500 break;
1502 case MONO_PATCH_INFO_SFLDA: {
1503 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1504 mono_error_assert_ok (error);
1506 if (mono_class_field_is_special_static (patch_info->data.field)) {
1507 gpointer addr = NULL;
1509 mono_domain_lock (domain);
1510 if (domain->special_static_fields)
1511 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1512 mono_domain_unlock (domain);
1513 g_assert (addr);
1514 return addr;
1517 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (!method || mono_class_needs_cctor_run (vtable->klass, method)))
1518 /* Done by the generated code */
1520 else {
1521 if (run_cctors) {
1522 if (!mono_runtime_class_init_full (vtable, error)) {
1523 return NULL;
1527 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1528 break;
1530 case MONO_PATCH_INFO_RVA: {
1531 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1532 guint32 rva;
1534 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1535 target = mono_image_rva_map (patch_info->data.token->image, rva);
1536 break;
1538 case MONO_PATCH_INFO_R4:
1539 case MONO_PATCH_INFO_R8:
1540 target = patch_info->data.target;
1541 break;
1542 case MONO_PATCH_INFO_EXC_NAME:
1543 target = patch_info->data.name;
1544 break;
1545 case MONO_PATCH_INFO_LDSTR:
1546 target =
1547 mono_ldstr_checked (domain, patch_info->data.token->image,
1548 mono_metadata_token_index (patch_info->data.token->token), error);
1549 break;
1550 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1551 gpointer handle;
1552 MonoClass *handle_class;
1554 handle = mono_ldtoken_checked (patch_info->data.token->image,
1555 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1556 if (!mono_error_ok (error))
1557 return NULL;
1558 mono_class_init_internal (handle_class);
1559 mono_class_init_internal (mono_class_from_mono_type_internal ((MonoType *)handle));
1561 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1562 if (!mono_error_ok (error))
1563 return NULL;
1564 break;
1566 case MONO_PATCH_INFO_LDTOKEN: {
1567 gpointer handle;
1568 MonoClass *handle_class;
1570 handle = mono_ldtoken_checked (patch_info->data.token->image,
1571 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1572 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1573 mono_class_init_internal (handle_class);
1575 target = handle;
1576 break;
1578 case MONO_PATCH_INFO_DECLSEC:
1579 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1580 break;
1581 case MONO_PATCH_INFO_ICALL_ADDR:
1582 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1583 /* run_cctors == 0 -> AOT */
1584 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1585 if (run_cctors) {
1586 target = mono_lookup_pinvoke_call_internal (patch_info->data.method, error);
1587 if (!target) {
1588 if (mono_aot_only)
1589 return NULL;
1590 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));
1592 } else {
1593 target = NULL;
1595 } else {
1596 target = mono_lookup_internal_call (patch_info->data.method);
1598 if (!target && run_cctors)
1599 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1601 break;
1602 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1603 target = mono_thread_interruption_request_flag ();
1604 break;
1605 case MONO_PATCH_INFO_METHOD_RGCTX:
1606 target = mini_method_get_rgctx (patch_info->data.method);
1607 break;
1608 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1609 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1611 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1612 break;
1614 case MONO_PATCH_INFO_BB_OVF:
1615 case MONO_PATCH_INFO_EXC_OVF:
1616 case MONO_PATCH_INFO_GOT_OFFSET:
1617 case MONO_PATCH_INFO_NONE:
1618 break;
1619 case MONO_PATCH_INFO_RGCTX_FETCH: {
1620 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1622 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1623 break;
1625 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1626 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1627 if (!run_cctors)
1628 /* AOT, not needed */
1629 target = NULL;
1630 else
1631 target = mono_arch_get_seq_point_info (domain, code);
1632 break;
1633 #endif
1634 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1635 int card_table_shift_bits;
1636 gpointer card_table_mask;
1638 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1639 break;
1641 case MONO_PATCH_INFO_GC_NURSERY_START: {
1642 int shift_bits;
1643 size_t size;
1645 target = mono_gc_get_nursery (&shift_bits, &size);
1646 break;
1648 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1649 int shift_bits;
1650 size_t size;
1652 mono_gc_get_nursery (&shift_bits, &size);
1654 target = (gpointer)(gssize)shift_bits;
1655 break;
1657 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1658 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1659 break;
1661 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1662 target = NULL;
1663 break;
1665 case MONO_PATCH_INFO_LDSTR_LIT: {
1666 int len;
1667 char *s;
1669 len = strlen ((const char *)patch_info->data.target);
1670 s = (char *)mono_domain_alloc0 (domain, len + 1);
1671 memcpy (s, patch_info->data.target, len);
1672 target = s;
1674 break;
1676 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1677 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1678 break;
1679 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1680 target = (gpointer)mono_tls_get_tls_getter ((MonoTlsKey)patch_info->data.index);
1681 break;
1682 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1683 target = (gpointer)mono_tls_get_tls_setter ((MonoTlsKey)patch_info->data.index);
1684 break;
1685 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1686 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1687 break;
1689 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1690 target = (gpointer) &mono_profiler_state.exception_clause_count;
1691 break;
1693 default:
1694 g_assert_not_reached ();
1697 return (gpointer)target;
1701 * mini_register_jump_site:
1703 * Register IP as a jump/tailcall site which calls METHOD.
1704 * This is needed because common_call_trampoline () cannot patch
1705 * the call site because the caller ip is not available for jumps.
1707 void
1708 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1710 MonoJumpList *jlist;
1712 MonoMethod *shared_method = mini_method_to_shared (method);
1713 method = shared_method ? shared_method : method;
1715 mono_domain_lock (domain);
1716 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1717 if (!jlist) {
1718 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1719 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1721 jlist->list = g_slist_prepend (jlist->list, ip);
1722 mono_domain_unlock (domain);
1726 * mini_patch_jump_sites:
1728 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1730 void
1731 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1733 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1735 if (!hash)
1736 return;
1738 MonoJumpInfo patch_info;
1739 MonoJumpList *jlist;
1740 GSList *tmp;
1742 /* The caller/callee might use different instantiations */
1743 MonoMethod *shared_method = mini_method_to_shared (method);
1744 method = shared_method ? shared_method : method;
1746 mono_domain_lock (domain);
1747 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1748 if (jlist)
1749 g_hash_table_remove (hash, method);
1750 mono_domain_unlock (domain);
1751 if (jlist) {
1752 patch_info.next = NULL;
1753 patch_info.ip.i = 0;
1754 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1755 patch_info.data.method = method;
1757 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1758 for (tmp = jlist->list; tmp; tmp = tmp->next)
1759 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1760 #else
1761 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1762 // for gshared methods
1763 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1764 ERROR_DECL (error);
1765 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1766 mono_error_assert_ok (error);
1768 #endif
1772 void
1773 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1775 MonoGenericInst *inst;
1776 int i;
1778 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1780 if (context && context->class_inst) {
1781 inst = context->class_inst;
1782 for (i = 0; i < inst->type_argc; ++i) {
1783 MonoType *type = inst->type_argv [i];
1785 if (mini_is_gsharedvt_gparam (type))
1786 gsctx->is_gsharedvt = TRUE;
1789 if (context && context->method_inst) {
1790 inst = context->method_inst;
1792 for (i = 0; i < inst->type_argc; ++i) {
1793 MonoType *type = inst->type_argv [i];
1795 if (mini_is_gsharedvt_gparam (type))
1796 gsctx->is_gsharedvt = TRUE;
1802 * LOCKING: Acquires the jit code hash lock.
1804 MonoJitInfo*
1805 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1807 MonoJitInfo *ji;
1808 static gboolean inited = FALSE;
1809 static int lookups = 0;
1810 static int failed_lookups = 0;
1812 mono_domain_jit_code_hash_lock (domain);
1813 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1814 if (!ji && shared) {
1815 /* Try generic sharing */
1816 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1817 if (ji && !ji->has_generic_jit_info)
1818 ji = NULL;
1819 if (!inited) {
1820 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1821 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1822 inited = TRUE;
1825 ++lookups;
1826 if (!ji)
1827 ++failed_lookups;
1829 mono_domain_jit_code_hash_unlock (domain);
1831 return ji;
1834 static MonoJitInfo*
1835 lookup_method (MonoDomain *domain, MonoMethod *method)
1837 ERROR_DECL (error);
1838 MonoJitInfo *ji;
1839 MonoMethod *shared;
1841 ji = mini_lookup_method (domain, method, NULL);
1843 if (!ji) {
1844 if (!mono_method_is_generic_sharable (method, FALSE))
1845 return NULL;
1846 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1847 mono_error_assert_ok (error);
1848 ji = mini_lookup_method (domain, method, shared);
1851 return ji;
1854 MonoClass*
1855 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1857 ERROR_DECL (error);
1858 MonoClass *klass;
1860 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1861 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1862 if (context) {
1863 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1864 mono_error_cleanup (error); /* FIXME don't swallow the error */
1866 } else {
1867 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1868 mono_error_cleanup (error); /* FIXME don't swallow the error */
1870 if (klass)
1871 mono_class_init_internal (klass);
1872 return klass;
1875 #if ENABLE_JIT_MAP
1876 static FILE* perf_map_file;
1878 void
1879 mono_enable_jit_map (void)
1881 if (!perf_map_file) {
1882 char name [64];
1883 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1884 unlink (name);
1885 perf_map_file = fopen (name, "w");
1889 void
1890 mono_emit_jit_tramp (void *start, int size, const char *desc)
1892 if (perf_map_file)
1893 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1896 void
1897 mono_emit_jit_map (MonoJitInfo *jinfo)
1899 if (perf_map_file) {
1900 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1901 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1902 g_free (name);
1906 gboolean
1907 mono_jit_map_is_enabled (void)
1909 return perf_map_file != NULL;
1912 #endif
1914 static void
1915 no_gsharedvt_in_wrapper (void)
1917 g_assert_not_reached ();
1921 Overall algorithm:
1923 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.
1924 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1925 Dependency management in this case is too complex to justify implementing it.
1927 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1929 TODO:
1930 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1931 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1932 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1933 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1935 typedef struct {
1936 MonoMethod *method;
1937 MonoDomain *domain;
1938 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1939 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1940 int threads_waiting; /* Number of threads waiting on this job */
1941 gboolean has_cond; /* True if @cond was initialized */
1942 gboolean done; /* True if the method finished JIT'ing */
1943 MonoCoopCond cond; /* Cond sleeping threads wait one */
1944 } JitCompilationEntry;
1946 typedef struct {
1947 GPtrArray *in_flight_methods; //JitCompilationEntry*
1948 MonoCoopMutex lock;
1949 } JitCompilationData;
1952 Timeout, in millisecounds, that we wait other threads to finish JITing.
1953 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.
1955 #define MAX_JIT_TIMEOUT_MS 1000
1958 static JitCompilationData compilation_data;
1959 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
1961 static void
1962 mini_jit_init_job_control (void)
1964 mono_coop_mutex_init (&compilation_data.lock);
1965 compilation_data.in_flight_methods = g_ptr_array_new ();
1968 static void
1969 lock_compilation_data (void)
1971 mono_coop_mutex_lock (&compilation_data.lock);
1974 static void
1975 unlock_compilation_data (void)
1977 mono_coop_mutex_unlock (&compilation_data.lock);
1980 static JitCompilationEntry*
1981 find_method (MonoMethod *method, MonoDomain *domain)
1983 int i;
1984 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1985 JitCompilationEntry *e = (JitCompilationEntry*)compilation_data.in_flight_methods->pdata [i];
1986 if (e->method == method && e->domain == domain)
1987 return e;
1990 return NULL;
1993 static void
1994 add_current_thread (MonoJitTlsData *jit_tls)
1996 ++jit_tls->active_jit_methods;
1999 static void
2000 unref_jit_entry (JitCompilationEntry *entry)
2002 --entry->ref_count;
2003 if (entry->ref_count)
2004 return;
2005 if (entry->has_cond)
2006 mono_coop_cond_destroy (&entry->cond);
2007 g_free (entry);
2011 * Returns true if this method waited successfully for another thread to JIT it
2013 static gboolean
2014 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
2016 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2017 JitCompilationEntry *entry;
2019 static gboolean inited;
2020 if (!inited) {
2021 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
2022 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
2023 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
2024 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
2025 inited = TRUE;
2028 lock_compilation_data ();
2030 if (!(entry = find_method (method, domain))) {
2031 entry = g_new0 (JitCompilationEntry, 1);
2032 entry->method = method;
2033 entry->domain = domain;
2034 entry->compilation_count = entry->ref_count = 1;
2035 g_ptr_array_add (compilation_data.in_flight_methods, entry);
2036 g_assert (find_method (method, domain) == entry);
2037 add_current_thread (jit_tls);
2039 unlock_compilation_data ();
2040 return FALSE;
2041 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2042 //We can't suspend the current thread if it's already JITing a method.
2043 //Dependency management is too compilated and we want to get rid of this anyways.
2045 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2046 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2048 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2049 ++entry->compilation_count;
2050 ++jit_methods_multiple;
2051 ++jit_tls->active_jit_methods;
2053 unlock_compilation_data ();
2054 return FALSE;
2055 } else {
2056 ++jit_methods_waited;
2057 ++entry->ref_count;
2059 if (!entry->has_cond) {
2060 mono_coop_cond_init (&entry->cond);
2061 entry->has_cond = TRUE;
2064 while (TRUE) {
2065 ++entry->threads_waiting;
2067 g_assert (entry->has_cond);
2068 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2069 --entry->threads_waiting;
2071 if (entry->done) {
2072 unref_jit_entry (entry);
2073 unlock_compilation_data ();
2074 return TRUE;
2075 } else {
2076 //We hit the timeout or a spurious wakeup, fallback to JITing
2077 g_assert (entry->ref_count > 1);
2078 unref_jit_entry (entry);
2079 ++jit_spurious_wakeups_or_timeouts;
2081 ++entry->compilation_count;
2082 ++jit_methods_multiple;
2083 ++jit_tls->active_jit_methods;
2085 unlock_compilation_data ();
2086 return FALSE;
2092 static void
2093 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2095 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2097 lock_compilation_data ();
2099 g_assert (jit_tls->active_jit_methods > 0);
2100 --jit_tls->active_jit_methods;
2102 JitCompilationEntry *entry = find_method (method, target_domain);
2103 g_assert (entry); // It would be weird to fail
2104 entry->done = TRUE;
2106 if (entry->threads_waiting) {
2107 g_assert (entry->has_cond);
2108 mono_coop_cond_broadcast (&entry->cond);
2111 if (--entry->compilation_count == 0) {
2112 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2113 unref_jit_entry (entry);
2116 unlock_compilation_data ();
2119 static MonoJitInfo*
2120 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2122 MonoDomain *domain = mono_get_root_domain ();
2123 MonoJitInfo *jinfo;
2124 guint8 *uw_info;
2125 guint32 info_len;
2127 if (info->uw_info) {
2128 uw_info = info->uw_info;
2129 info_len = info->uw_info_len;
2130 } else {
2131 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2134 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2135 jinfo->d.method = wrapper;
2136 jinfo->code_start = info->code;
2137 jinfo->code_size = info->code_size;
2138 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2140 if (!info->uw_info)
2141 g_free (uw_info);
2143 return jinfo;
2146 static gpointer
2147 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2149 MonoJitInfo *jinfo;
2150 gpointer code;
2152 if (mono_llvm_only) {
2153 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2154 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2156 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2158 * These wrappers are only created for signatures which are in the program, but
2159 * sometimes we load methods too eagerly and have to create them even if they
2160 * will never be called.
2162 return (gpointer)no_gsharedvt_in_wrapper;
2167 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2168 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2169 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2171 if (!piinfo->addr) {
2172 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2173 piinfo->addr = mono_lookup_internal_call (method);
2174 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2175 #ifdef HOST_WIN32
2176 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);
2177 #else
2178 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);
2179 #endif
2180 else {
2181 ERROR_DECL (ignored_error);
2182 mono_lookup_pinvoke_call_internal (method, ignored_error);
2183 mono_error_cleanup (ignored_error);
2187 MonoMethod *nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2188 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2189 return_val_if_nok (error, NULL);
2191 code = mono_get_addr_from_ftnptr (compiled_method);
2192 jinfo = mono_jit_info_table_find (target_domain, code);
2193 if (!jinfo)
2194 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2195 if (jinfo)
2196 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2197 return code;
2198 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2199 const char *name = method->name;
2200 char *full_name;
2201 MonoMethod *nm;
2203 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2204 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2205 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2206 g_assert (mi);
2208 * We need to make sure this wrapper
2209 * is compiled because it might end up
2210 * in an (M)RGCTX if generic sharing
2211 * is enabled, and would be called
2212 * indirectly. If it were a
2213 * trampoline we'd try to patch that
2214 * indirect call, which is not
2215 * possible.
2217 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2218 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2219 if (mono_llvm_only) {
2220 nm = mono_marshal_get_delegate_invoke (method, NULL);
2221 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2222 return_val_if_nok (error, NULL);
2223 return mono_get_addr_from_ftnptr (compiled_ptr);
2226 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2227 if (mono_use_interpreter)
2228 return NULL;
2230 return mono_create_delegate_trampoline (target_domain, method->klass);
2231 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2232 nm = mono_marshal_get_delegate_begin_invoke (method);
2233 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2234 return_val_if_nok (error, NULL);
2235 return mono_get_addr_from_ftnptr (compiled_ptr);
2236 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2237 nm = mono_marshal_get_delegate_end_invoke (method);
2238 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2239 return_val_if_nok (error, NULL);
2240 return mono_get_addr_from_ftnptr (compiled_ptr);
2244 full_name = mono_method_full_name (method, TRUE);
2245 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2246 g_free (full_name);
2247 return NULL;
2250 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2251 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2253 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2254 static MonoTrampInfo *in_tinfo, *out_tinfo;
2255 MonoTrampInfo *tinfo;
2256 MonoJitInfo *jinfo;
2257 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2259 if (is_in && in_tinfo)
2260 return in_tinfo->code;
2261 else if (!is_in && out_tinfo)
2262 return out_tinfo->code;
2265 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2266 * works.
2267 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2269 if (mono_ee_features.use_aot_trampolines)
2270 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2271 else
2272 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2273 jinfo = create_jit_info_for_trampoline (method, tinfo);
2274 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2275 if (is_in)
2276 in_tinfo = tinfo;
2277 else
2278 out_tinfo = tinfo;
2279 return tinfo->code;
2283 return NULL;
2286 static gpointer
2287 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2289 MonoDomain *target_domain, *domain = mono_domain_get ();
2290 MonoJitInfo *info;
2291 gpointer code = NULL, p;
2292 MonoJitInfo *ji;
2293 MonoJitICallInfo *callinfo = NULL;
2294 WrapperInfo *winfo = NULL;
2295 gboolean use_interp = FALSE;
2297 error_init (error);
2299 if (mono_ee_features.force_use_interpreter && !jit_only)
2300 use_interp = TRUE;
2301 if (!use_interp && mono_interp_only_classes) {
2302 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2303 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2304 use_interp = TRUE;
2307 if (use_interp) {
2308 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2309 if (code)
2310 return code;
2313 if (mono_llvm_only)
2314 /* Should be handled by the caller */
2315 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2318 * ICALL wrappers are handled specially, since there is only one copy of them
2319 * shared by all appdomains.
2321 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2322 winfo = mono_marshal_get_wrapper_info (method);
2323 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2324 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2325 g_assert (callinfo);
2327 /* Must be domain neutral since there is only one copy */
2328 opt |= MONO_OPT_SHARED;
2329 } else {
2330 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2331 opt &= ~MONO_OPT_SHARED;
2334 if (opt & MONO_OPT_SHARED)
2335 target_domain = mono_get_root_domain ();
2336 else
2337 target_domain = domain;
2339 if (method->wrapper_type == MONO_WRAPPER_OTHER) {
2340 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2342 g_assert (info);
2343 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2344 MonoGenericContext *ctx = NULL;
2345 if (method->is_inflated)
2346 ctx = mono_method_get_context (method);
2347 method = info->d.synchronized_inner.method;
2348 if (ctx) {
2349 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2350 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2355 lookup_start:
2356 info = lookup_method (target_domain, method);
2357 if (info) {
2358 /* We can't use a domain specific method in another domain */
2359 if (! ((domain != target_domain) && !info->domain_neutral)) {
2360 MonoVTable *vtable;
2362 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2363 vtable = mono_class_vtable_checked (domain, method->klass, error);
2364 if (!is_ok (error))
2365 return NULL;
2366 g_assert (vtable);
2367 if (!mono_runtime_class_init_full (vtable, error))
2368 return NULL;
2369 return mono_create_ftnptr (target_domain, info->code_start);
2373 #ifdef MONO_USE_AOT_COMPILER
2374 if (opt & MONO_OPT_AOT) {
2375 MonoDomain *domain = NULL;
2377 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_OTHER) {
2378 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2379 g_assert (info);
2380 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2381 /* AOT'd wrappers for interp must be owned by root domain */
2382 domain = mono_get_root_domain ();
2385 if (!domain)
2386 domain = mono_domain_get ();
2388 mono_class_init_internal (method->klass);
2390 code = mono_aot_get_method (domain, method, error);
2391 if (code) {
2392 MonoVTable *vtable;
2394 if (mono_gc_is_critical_method (method)) {
2396 * The suspend code needs to be able to lookup these methods by ip in async context,
2397 * so preload their jit info.
2399 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2400 g_assert (ji);
2404 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2405 * This is not a problem, since it will be initialized when the method is first
2406 * called by init_method ().
2408 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2409 vtable = mono_class_vtable_checked (domain, method->klass, error);
2410 mono_error_assert_ok (error);
2411 if (!mono_runtime_class_init_full (vtable, error))
2412 return NULL;
2415 if (!is_ok (error))
2416 return NULL;
2418 #endif
2420 if (!code) {
2421 code = compile_special (method, target_domain, error);
2423 if (!mono_error_ok (error))
2424 return NULL;
2427 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_OTHER) {
2428 if (mono_llvm_only) {
2429 /* Signal to the caller that AOTed code is not found */
2430 return NULL;
2432 code = mini_get_interp_callbacks ()->create_method_pointer (method, TRUE, error);
2434 if (!mono_error_ok (error))
2435 return NULL;
2438 if (!code) {
2439 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2440 char *full_name = mono_type_get_full_name (method->klass);
2441 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type '%s', is not fully instantiated.", full_name);
2442 g_free (full_name);
2443 return NULL;
2446 if (mono_aot_only) {
2447 char *fullname = mono_method_get_full_name (method);
2448 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);
2449 g_free (fullname);
2451 return NULL;
2454 if (wait_or_register_method_to_compile (method, target_domain))
2455 goto lookup_start;
2456 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2457 unregister_method_for_compile (method, target_domain);
2459 if (!mono_error_ok (error))
2460 return NULL;
2462 if (!code && mono_llvm_only) {
2463 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2464 g_assert_not_reached ();
2467 if (!code)
2468 return NULL;
2470 //FIXME mini_jit_info_table_find doesn't work yet under wasm due to code_start/code_end issues.
2471 #ifndef HOST_WASM
2472 if ((method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC)) {
2473 MonoDomain *d;
2476 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2478 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2479 g_assert (ji);
2481 #endif
2483 p = mono_create_ftnptr (target_domain, code);
2485 if (callinfo) {
2486 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2487 mono_loader_lock ();
2488 mono_jit_lock ();
2489 if (!callinfo->wrapper) {
2490 callinfo->wrapper = p;
2491 mono_register_jit_icall_wrapper (callinfo, p);
2493 mono_jit_unlock ();
2494 mono_loader_unlock ();
2497 return p;
2500 gpointer
2501 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2503 gpointer code;
2505 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2506 return code;
2510 * mono_jit_compile_method_jit_only:
2512 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2514 gpointer
2515 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2517 gpointer code;
2519 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2520 return code;
2523 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2524 static void
2525 invalidated_delegate_trampoline (char *desc)
2527 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2528 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2529 desc);
2531 #endif
2534 * mono_jit_free_method:
2536 * Free all memory allocated by the JIT for METHOD.
2538 static void
2539 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2541 MonoJitDynamicMethodInfo *ji;
2542 gboolean destroy = TRUE, removed;
2543 GHashTableIter iter;
2544 MonoJumpList *jlist;
2545 MonoJitDomainInfo *info = domain_jit_info (domain);
2547 g_assert (method->dynamic);
2549 if (mono_use_interpreter) {
2550 mono_domain_jit_code_hash_lock (domain);
2551 /* InterpMethod is allocated in the domain mempool. We might haven't
2552 * allocated an InterpMethod for this instance yet */
2553 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2554 mono_domain_jit_code_hash_unlock (domain);
2557 mono_domain_lock (domain);
2558 ji = mono_dynamic_code_hash_lookup (domain, method);
2559 mono_domain_unlock (domain);
2561 if (!ji)
2562 return;
2564 mono_debug_remove_method (method, domain);
2565 mono_lldb_remove_method (domain, method, ji);
2567 mono_domain_lock (domain);
2568 g_hash_table_remove (info->dynamic_code_hash, method);
2569 mono_domain_jit_code_hash_lock (domain);
2570 removed = mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2571 g_assert (removed);
2572 mono_domain_jit_code_hash_unlock (domain);
2573 g_hash_table_remove (info->jump_trampoline_hash, method);
2574 g_hash_table_remove (info->seq_points, method);
2576 ji->ji->seq_points = NULL;
2578 /* requires the domain lock - took above */
2579 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2581 /* Remove jump targets in this method */
2582 g_hash_table_iter_init (&iter, info->jump_target_hash);
2583 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2584 GSList *tmp, *remove;
2586 remove = NULL;
2587 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2588 guint8 *ip = (guint8 *)tmp->data;
2590 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2591 remove = g_slist_prepend (remove, tmp);
2593 for (tmp = remove; tmp; tmp = tmp->next) {
2594 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2596 g_slist_free (remove);
2598 mono_domain_unlock (domain);
2600 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2601 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2603 * Instead of freeing the code, change it to call an error routine
2604 * so people can fix their code.
2606 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2607 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2609 g_free (type);
2610 mono_arch_invalidate_method (ji->ji, (gpointer)invalidated_delegate_trampoline, (gpointer)type_and_method);
2611 destroy = FALSE;
2613 #endif
2616 * This needs to be done before freeing code_mp, since the code address is the
2617 * key in the table, so if we free the code_mp first, another thread can grab the
2618 * same code address and replace our entry in the table.
2620 mono_jit_info_table_remove (domain, ji->ji);
2622 if (destroy)
2623 mono_code_manager_destroy (ji->code_mp);
2624 g_free (ji);
2627 gpointer
2628 mono_jit_search_all_backends_for_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **out_ji)
2630 gpointer code;
2631 MonoJitInfo *ji;
2633 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
2634 if (!code) {
2635 ERROR_DECL (oerror);
2637 /* Might be AOTed code */
2638 mono_class_init_internal (method->klass);
2639 code = mono_aot_get_method (domain, method, oerror);
2640 if (code) {
2641 mono_error_assert_ok (oerror);
2642 ji = mono_jit_info_table_find (domain, code);
2643 } else {
2644 if (!is_ok (oerror))
2645 mono_error_cleanup (oerror);
2647 /* Might be interpreted */
2648 ji = mini_get_interp_callbacks ()->find_jit_info (domain, method);
2652 *out_ji = ji;
2654 return code;
2657 gpointer
2658 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2660 MonoDomain *target_domain;
2661 MonoJitInfo *info;
2663 if (default_opt & MONO_OPT_SHARED)
2664 target_domain = mono_get_root_domain ();
2665 else
2666 target_domain = domain;
2668 info = lookup_method (target_domain, method);
2669 if (info) {
2670 /* We can't use a domain specific method in another domain */
2671 if (! ((domain != target_domain) && !info->domain_neutral)) {
2672 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2673 if (ji)
2674 *ji = info;
2675 return info->code_start;
2679 if (ji)
2680 *ji = NULL;
2681 return NULL;
2684 static guint32 bisect_opt = 0;
2685 static GHashTable *bisect_methods_hash = NULL;
2687 void
2688 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2690 FILE *file;
2691 char method_name [2048];
2693 bisect_opt = opt;
2694 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2695 g_assert (bisect_methods_hash);
2697 file = fopen (method_list_filename, "r");
2698 g_assert (file);
2700 while (fgets (method_name, sizeof (method_name), file)) {
2701 size_t len = strlen (method_name);
2702 g_assert (len > 0);
2703 g_assert (method_name [len - 1] == '\n');
2704 method_name [len - 1] = 0;
2705 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2707 g_assert (feof (file));
2710 gboolean mono_do_single_method_regression = FALSE;
2711 guint32 mono_single_method_regression_opt = 0;
2712 MonoMethod *mono_current_single_method;
2713 GSList *mono_single_method_list;
2714 GHashTable *mono_single_method_hash;
2716 guint32
2717 mono_get_optimizations_for_method (MonoMethod *method, guint32 opt)
2719 g_assert (method);
2721 if (bisect_methods_hash) {
2722 char *name = mono_method_full_name (method, TRUE);
2723 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2724 g_free (name);
2725 if (res)
2726 return opt | bisect_opt;
2728 if (!mono_do_single_method_regression)
2729 return opt;
2730 if (!mono_current_single_method) {
2731 if (!mono_single_method_hash)
2732 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2733 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2734 g_hash_table_insert (mono_single_method_hash, method, method);
2735 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2737 return opt;
2739 if (method == mono_current_single_method)
2740 return mono_single_method_regression_opt;
2741 return opt;
2744 gpointer
2745 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2747 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2750 typedef struct {
2751 MonoMethod *method;
2752 gpointer compiled_method;
2753 gpointer runtime_invoke;
2754 MonoVTable *vtable;
2755 MonoDynCallInfo *dyn_call_info;
2756 MonoClass *ret_box_class;
2757 MonoMethodSignature *sig;
2758 gboolean gsharedvt_invoke;
2759 gboolean use_interp;
2760 gpointer *wrapper_arg;
2761 } RuntimeInvokeInfo;
2763 static RuntimeInvokeInfo*
2764 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2766 MonoMethod *invoke;
2767 RuntimeInvokeInfo *info;
2769 info = g_new0 (RuntimeInvokeInfo, 1);
2770 info->compiled_method = compiled_method;
2771 info->use_interp = use_interp;
2772 if (mono_llvm_only && method->string_ctor)
2773 info->sig = mono_marshal_get_string_ctor_signature (method);
2774 else
2775 info->sig = mono_method_signature_internal (method);
2777 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2778 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2779 if (!mono_error_ok (error))
2780 return NULL;
2781 g_assert (info->vtable);
2783 MonoMethodSignature *sig = info->sig;
2784 MonoType *ret_type;
2787 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2788 * in full-aot mode, so we use a slower, but more generic wrapper if
2789 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2791 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2792 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2793 gboolean supported = TRUE;
2794 int i;
2796 if (method->string_ctor)
2797 sig = mono_marshal_get_string_ctor_signature (method);
2799 for (i = 0; i < sig->param_count; ++i) {
2800 MonoType *t = sig->params [i];
2802 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
2803 supported = FALSE;
2806 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2807 supported = FALSE;
2809 if (supported) {
2810 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2811 if (mini_debug_options.dyn_runtime_invoke)
2812 g_assert (info->dyn_call_info);
2815 #endif
2817 ret_type = sig->ret;
2818 switch (ret_type->type) {
2819 case MONO_TYPE_VOID:
2820 break;
2821 case MONO_TYPE_I1:
2822 case MONO_TYPE_U1:
2823 case MONO_TYPE_I2:
2824 case MONO_TYPE_U2:
2825 case MONO_TYPE_I4:
2826 case MONO_TYPE_U4:
2827 case MONO_TYPE_I:
2828 case MONO_TYPE_U:
2829 case MONO_TYPE_I8:
2830 case MONO_TYPE_U8:
2831 case MONO_TYPE_BOOLEAN:
2832 case MONO_TYPE_CHAR:
2833 case MONO_TYPE_R4:
2834 case MONO_TYPE_R8:
2835 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2836 break;
2837 case MONO_TYPE_PTR:
2838 info->ret_box_class = mono_defaults.int_class;
2839 break;
2840 case MONO_TYPE_STRING:
2841 case MONO_TYPE_CLASS:
2842 case MONO_TYPE_ARRAY:
2843 case MONO_TYPE_SZARRAY:
2844 case MONO_TYPE_OBJECT:
2845 break;
2846 case MONO_TYPE_GENERICINST:
2847 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2848 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2849 break;
2850 case MONO_TYPE_VALUETYPE:
2851 info->ret_box_class = mono_class_from_mono_type_internal (ret_type);
2852 break;
2853 default:
2854 g_assert_not_reached ();
2855 break;
2858 if (info->use_interp)
2859 return info;
2861 if (!info->dyn_call_info) {
2862 if (mono_llvm_only) {
2863 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2864 g_assert_not_reached ();
2865 #endif
2866 info->gsharedvt_invoke = TRUE;
2867 if (!callee_gsharedvt) {
2868 /* Invoke a gsharedvt out wrapper instead */
2869 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2870 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2872 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2873 info->wrapper_arg [0] = mini_llvmonly_add_method_wrappers (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2875 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2876 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2877 g_free (wrapper_sig);
2879 info->compiled_method = mono_jit_compile_method (wrapper, error);
2880 if (!mono_error_ok (error)) {
2881 g_free (info);
2882 return NULL;
2884 } else {
2885 /* Gsharedvt methods can be invoked the same way */
2886 /* The out wrapper has the same signature as the compiled gsharedvt method */
2887 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2889 info->wrapper_arg = (gpointer*)(mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL);
2891 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2892 g_free (wrapper_sig);
2895 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2896 if (!mono_error_ok (error)) {
2897 g_free (info);
2898 return NULL;
2902 return info;
2905 static MonoObject*
2906 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2908 MonoMethodSignature *sig = info->sig;
2909 MonoDomain *domain = mono_domain_get ();
2910 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2911 gpointer *args;
2912 gpointer retval_ptr;
2913 guint8 retval [256];
2914 gpointer *param_refs;
2915 int i, pindex;
2917 error_init (error);
2919 g_assert (info->gsharedvt_invoke);
2922 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2923 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2924 * signatures, so we only have to generate runtime invoke wrappers for these
2925 * signatures.
2926 * This code also handles invocation of gsharedvt methods directly, no
2927 * out wrappers are used in that case.
2929 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2930 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2931 pindex = 0;
2933 * The runtime invoke wrappers expects pointers to primitive types, so have to
2934 * use indirections.
2936 if (sig->hasthis)
2937 args [pindex ++] = &obj;
2938 if (sig->ret->type != MONO_TYPE_VOID) {
2939 retval_ptr = (gpointer)&retval;
2940 args [pindex ++] = &retval_ptr;
2942 for (i = 0; i < sig->param_count; ++i) {
2943 MonoType *t = sig->params [i];
2945 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
2946 MonoClass *klass = mono_class_from_mono_type_internal (t);
2947 guint8 *nullable_buf;
2948 int size;
2950 size = mono_class_value_size (klass, NULL);
2951 nullable_buf = g_alloca (size);
2952 g_assert (nullable_buf);
2954 /* The argument pointed to by params [i] is either a boxed vtype or null */
2955 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2956 params [i] = nullable_buf;
2959 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2960 param_refs [i] = params [i];
2961 params [i] = &(param_refs [i]);
2963 args [pindex ++] = &params [i];
2965 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2966 args [pindex ++] = &info->wrapper_arg;
2968 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2970 runtime_invoke (NULL, args, exc, info->compiled_method);
2971 if (exc && *exc)
2972 return NULL;
2974 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2975 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2976 else
2977 return *(MonoObject**)retval;
2981 * mono_jit_runtime_invoke:
2982 * \param method: the method to invoke
2983 * \param obj: this pointer
2984 * \param params: array of parameter values.
2985 * \param exc: Set to the exception raised in the managed method.
2986 * \param error: error or caught exception object
2987 * If \p exc is NULL, \p error is thrown instead.
2988 * If coop is enabled, \p exc argument is ignored -
2989 * all exceptions are caught and propagated through \p error
2991 static MonoObject*
2992 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2994 MonoMethod *invoke, *callee;
2995 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2996 MonoDomain *domain = mono_domain_get ();
2997 MonoJitDomainInfo *domain_info;
2998 RuntimeInvokeInfo *info, *info2;
2999 MonoJitInfo *ji = NULL;
3000 gboolean callee_gsharedvt = FALSE;
3002 if (mono_ee_features.force_use_interpreter)
3003 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3005 error_init (error);
3006 if (exc)
3007 *exc = NULL;
3009 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
3010 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
3011 return NULL;
3014 domain_info = domain_jit_info (domain);
3016 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
3018 if (!info) {
3019 if (mono_security_core_clr_enabled ()) {
3021 * This might be redundant since mono_class_vtable () already does this,
3022 * but keep it just in case for moonlight.
3024 mono_class_setup_vtable (method->klass);
3025 if (mono_class_has_failure (method->klass)) {
3026 mono_error_set_for_class_failure (error, method->klass);
3027 if (exc)
3028 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
3029 return NULL;
3033 gpointer compiled_method;
3035 callee = method;
3036 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
3037 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3039 * Array Get/Set/Address methods. The JIT implements them using inline code
3040 * inside the runtime invoke wrappers, so no need to compile them.
3042 if (mono_aot_only) {
3044 * Call a wrapper, since the runtime invoke wrapper was not generated.
3046 MonoMethod *wrapper;
3048 wrapper = mono_marshal_get_array_accessor_wrapper (method);
3049 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
3050 callee = wrapper;
3051 } else {
3052 callee = NULL;
3056 gboolean use_interp = FALSE;
3058 if (callee) {
3059 compiled_method = mono_jit_compile_method_jit_only (callee, error);
3060 if (!compiled_method) {
3061 g_assert (!mono_error_ok (error));
3063 if (mono_use_interpreter)
3064 use_interp = TRUE;
3065 else
3066 return NULL;
3067 } else {
3068 if (mono_llvm_only) {
3069 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
3070 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3071 if (callee_gsharedvt)
3072 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
3075 if (!callee_gsharedvt)
3076 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
3078 } else {
3079 compiled_method = NULL;
3082 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
3083 if (!mono_error_ok (error))
3084 return NULL;
3086 mono_domain_lock (domain);
3087 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
3088 mono_domain_unlock (domain);
3089 if (info2) {
3090 g_free (info);
3091 info = info2;
3096 * We need this here because mono_marshal_get_runtime_invoke can place
3097 * the helper method in System.Object and not the target class.
3099 if (!mono_runtime_class_init_full (info->vtable, error)) {
3100 if (exc)
3101 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3102 return NULL;
3105 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3106 we always catch the exception and propagate it through the MonoError */
3107 gboolean catchExcInMonoError =
3108 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3109 MonoObject *invoke_exc = NULL;
3110 if (catchExcInMonoError)
3111 exc = &invoke_exc;
3113 /* The wrappers expect this to be initialized to NULL */
3114 if (exc)
3115 *exc = NULL;
3117 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3118 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3119 if (info->dyn_call_info) {
3120 if (!dyn_runtime_invoke) {
3121 mono_domain_lock (domain);
3123 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3124 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3125 if (!dyn_runtime_invoke && mono_use_interpreter) {
3126 info->use_interp = TRUE;
3127 info->dyn_call_info = NULL;
3128 } else if (!mono_error_ok (error)) {
3129 mono_domain_unlock (domain);
3130 return NULL;
3132 mono_domain_unlock (domain);
3135 if (info->dyn_call_info) {
3136 MonoMethodSignature *sig = mono_method_signature_internal (method);
3137 gpointer *args;
3138 int i, pindex, buf_size;
3139 guint8 *buf;
3140 guint8 retval [256];
3142 /* Convert the arguments to the format expected by start_dyn_call () */
3143 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3144 pindex = 0;
3145 if (sig->hasthis)
3146 args [pindex ++] = &obj;
3147 for (i = 0; i < sig->param_count; ++i) {
3148 MonoType *t = sig->params [i];
3150 if (t->byref) {
3151 args [pindex ++] = &params [i];
3152 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3153 args [pindex ++] = &params [i];
3154 } else {
3155 args [pindex ++] = params [i];
3159 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3161 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3162 buf = g_alloca (buf_size);
3163 memset (buf, 0, buf_size);
3164 g_assert (buf);
3166 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3168 dyn_runtime_invoke (buf, exc, info->compiled_method);
3169 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3171 if (catchExcInMonoError && *exc != NULL) {
3172 mono_error_set_exception_instance (error, (MonoException*) *exc);
3173 return NULL;
3176 if (info->ret_box_class)
3177 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3178 else
3179 return *(MonoObject**)retval;
3181 #endif
3183 MonoObject *result;
3185 if (info->use_interp) {
3186 result = mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3187 return_val_if_nok (error, NULL);
3188 } else if (mono_llvm_only) {
3189 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3190 if (!is_ok (error))
3191 return NULL;
3192 } else {
3193 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3195 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3197 if (catchExcInMonoError && *exc != NULL) {
3198 ((MonoException *)(*exc))->caught_in_unmanaged = TRUE;
3199 mono_error_set_exception_instance (error, (MonoException*) *exc);
3201 return result;
3204 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3206 MonoException *exc = NULL;
3207 MonoJitInfo *ji;
3208 MonoContext mctx;
3209 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3210 MONO_SIG_HANDLER_GET_CONTEXT;
3212 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3214 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3216 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3217 if (mono_arch_is_int_overflow (ctx, info))
3219 * The spec says this throws ArithmeticException, but MS throws the derived
3220 * OverflowException.
3222 exc = mono_get_exception_overflow ();
3223 else
3224 exc = mono_get_exception_divide_by_zero ();
3225 #else
3226 exc = mono_get_exception_divide_by_zero ();
3227 #endif
3229 if (!ji) {
3230 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3231 goto exit;
3233 mono_sigctx_to_monoctx (ctx, &mctx);
3234 mono_handle_native_crash ("SIGFPE", &mctx, info);
3235 if (mono_do_crash_chaining) {
3236 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3237 goto exit;
3241 mono_arch_handle_exception (ctx, exc);
3243 exit:
3244 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3247 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3249 MonoContext mctx;
3250 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3251 MONO_SIG_HANDLER_GET_CONTEXT;
3253 if (mono_runtime_get_no_exec ())
3254 exit (1);
3256 mono_sigctx_to_monoctx (ctx, &mctx);
3257 mono_handle_native_crash ("SIGILL", &mctx, info);
3258 if (mono_do_crash_chaining) {
3259 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3260 return;
3263 g_assert_not_reached ();
3266 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3268 #define HAVE_SIG_INFO
3269 #define MONO_SIG_HANDLER_DEBUG 1 // "with_fault_addr" but could be extended in future, so "debug"
3271 #ifdef MONO_SIG_HANDLER_DEBUG
3272 // Same as MONO_SIG_HANDLER_FUNC but debug_fault_addr is added to params, and no_optimize.
3273 // The Krait workaround is not needed here, due to this not actually being the signal handler,
3274 // so MONO_SIGNAL_HANDLER_FUNC is combined into it.
3275 #define MONO_SIG_HANDLER_FUNC_DEBUG(access, ftn) access MONO_NO_OPTIMIZATION void ftn \
3276 (int _dummy, MONO_SIG_HANDLER_INFO_TYPE *_info, void *context, void * volatile debug_fault_addr G_GNUC_UNUSED)
3277 #define MONO_SIG_HANDLER_PARAMS_DEBUG MONO_SIG_HANDLER_PARAMS, debug_fault_addr
3278 #endif
3280 #endif
3282 static gboolean
3283 is_addr_implicit_null_check (void *addr)
3285 /* implicit null checks are only expected to work on the first page. larger
3286 * offsets are expected to have an explicit null check */
3287 return addr <= GUINT_TO_POINTER (mono_target_pagesize ());
3290 // This function is separate from mono_sigsegv_signal_handler
3291 // so debug_fault_addr can be seen in debugger stacks.
3292 #ifdef MONO_SIG_HANDLER_DEBUG
3293 MONO_NEVER_INLINE
3294 MONO_SIG_HANDLER_FUNC_DEBUG (static, mono_sigsegv_signal_handler_debug)
3295 #else
3296 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3297 #endif
3299 MonoJitInfo *ji = NULL;
3300 MonoDomain *domain = mono_domain_get ();
3301 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3302 gpointer fault_addr = NULL;
3303 MonoContext mctx;
3305 #ifdef HAVE_SIG_INFO
3306 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3307 #else
3308 void *info = NULL;
3309 #endif
3310 MONO_SIG_HANDLER_GET_CONTEXT;
3312 mono_sigctx_to_monoctx (ctx, &mctx);
3314 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3315 if (mono_arch_is_single_step_event (info, ctx)) {
3316 mini_get_dbg_callbacks ()->single_step_event (ctx);
3317 return;
3318 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3319 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3320 return;
3322 #endif
3324 #if defined(HAVE_SIG_INFO)
3325 #if !defined(HOST_WIN32)
3326 fault_addr = info->si_addr;
3327 if (mono_aot_is_pagefault (info->si_addr)) {
3328 mono_aot_handle_pagefault (info->si_addr);
3329 return;
3331 #endif
3333 /* The thread might no be registered with the runtime */
3334 if (!mono_domain_get () || !jit_tls) {
3335 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3336 return;
3337 mono_handle_native_crash ("SIGSEGV", &mctx, info);
3338 if (mono_do_crash_chaining) {
3339 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3340 return;
3343 #endif
3345 if (domain)
3346 ji = mono_jit_info_table_find_internal (domain, mono_arch_ip_from_context (ctx), TRUE, TRUE);
3348 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3349 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3350 return;
3352 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3353 fault_addr = info->si_addr;
3354 if (fault_addr == NULL) {
3355 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3358 if (jit_tls && jit_tls->stack_size &&
3359 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3361 * The hard-guard page has been hit: there is not much we can do anymore
3362 * Print a hopefully clear message and abort.
3364 mono_handle_hard_stack_ovf (jit_tls, ji, &mctx, (guint8*)info->si_addr);
3365 g_assert_not_reached ();
3366 } else {
3367 /* The original handler might not like that it is executed on an altstack... */
3368 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3369 return;
3371 if (is_addr_implicit_null_check (info->si_addr)) {
3372 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3373 } else {
3374 mono_handle_native_crash ("SIGSEGV", &mctx, info);
3377 #else
3379 if (!ji) {
3380 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3381 return;
3383 mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3385 if (mono_do_crash_chaining) {
3386 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3387 return;
3391 if (is_addr_implicit_null_check (fault_addr)) {
3392 mono_arch_handle_exception (ctx, NULL);
3393 } else {
3394 mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
3396 #endif
3399 #ifdef MONO_SIG_HANDLER_DEBUG
3401 // This function is separate from mono_sigsegv_signal_handler_debug
3402 // so debug_fault_addr can be seen in debugger stacks.
3403 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3405 #ifdef HOST_WIN32
3406 gpointer const debug_fault_addr = (gpointer)MONO_SIG_HANDLER_GET_INFO () ->ep->ExceptionRecord->ExceptionInformation [1];
3407 #elif defined (HAVE_SIG_INFO)
3408 gpointer const debug_fault_addr = MONO_SIG_HANDLER_GET_INFO ()->si_addr;
3409 #else
3410 #error No extra parameter is passed, not even 0, to avoid any confusion.
3411 #endif
3412 mono_sigsegv_signal_handler_debug (MONO_SIG_HANDLER_PARAMS_DEBUG);
3415 #endif // MONO_SIG_HANDLER_DEBUG
3417 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3419 MonoException *exc;
3420 MONO_SIG_HANDLER_GET_CONTEXT;
3422 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3424 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3426 mono_arch_handle_exception (ctx, exc);
3428 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3431 #ifndef DISABLE_REMOTING
3432 /* mono_jit_create_remoting_trampoline:
3433 * @method: pointer to the method info
3435 * Creates a trampoline which calls the remoting functions. This
3436 * is used in the vtable of transparent proxies.
3438 * Returns: a pointer to the newly created code
3440 static gpointer
3441 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3443 MonoMethod *nm;
3444 guint8 *addr = NULL;
3446 error_init (error);
3448 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature_internal (method)->generic_param_count) {
3449 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3450 domain, NULL);
3453 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3454 (mono_method_signature_internal (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3455 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3456 else
3457 nm = method;
3458 return_val_if_nok (error, NULL);
3459 addr = (guint8 *)mono_compile_method_checked (nm, error);
3460 return_val_if_nok (error, NULL);
3461 return mono_get_addr_from_ftnptr (addr);
3463 #endif
3465 static G_GNUC_UNUSED void
3466 no_imt_trampoline (void)
3468 g_assert_not_reached ();
3471 static G_GNUC_UNUSED void
3472 no_vcall_trampoline (void)
3474 g_assert_not_reached ();
3477 static gpointer *vtable_trampolines;
3478 static int vtable_trampolines_size;
3480 gpointer
3481 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3483 int index = slot_index + MONO_IMT_SIZE;
3485 if (mono_llvm_only)
3486 return mini_llvmonly_get_vtable_trampoline (vt, slot_index, index);
3488 g_assert (slot_index >= - MONO_IMT_SIZE);
3489 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3490 mono_jit_lock ();
3491 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3492 int new_size;
3493 gpointer new_table;
3495 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3496 while (new_size <= index)
3497 new_size *= 2;
3498 new_table = g_new0 (gpointer, new_size);
3500 if (vtable_trampolines)
3501 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3502 g_free (vtable_trampolines);
3503 mono_memory_barrier ();
3504 vtable_trampolines = (void **)new_table;
3505 vtable_trampolines_size = new_size;
3507 mono_jit_unlock ();
3510 if (!vtable_trampolines [index])
3511 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3512 return vtable_trampolines [index];
3515 static gpointer
3516 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3518 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3521 static gboolean
3522 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3524 if (mono_llvm_only)
3525 return FALSE;
3527 gpointer *imt = (gpointer*)vt;
3528 imt -= MONO_IMT_SIZE;
3530 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3533 static gpointer
3534 create_delegate_method_ptr (MonoMethod *method, MonoError *error)
3536 gpointer func;
3538 if (method_is_dynamic (method)) {
3539 /* Creating a trampoline would leak memory */
3540 func = mono_compile_method_checked (method, error);
3541 return_val_if_nok (error, NULL);
3542 } else {
3543 gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
3544 return_val_if_nok (error, NULL);
3545 func = mono_create_ftnptr (mono_domain_get (), trampoline);
3547 return func;
3550 static void
3551 mini_init_delegate (MonoDelegateHandle delegate, MonoError *error)
3553 MonoDelegate *del = MONO_HANDLE_RAW (delegate);
3555 if (mono_use_interpreter) {
3556 mini_get_interp_callbacks ()->init_delegate (del, error);
3557 return_if_nok (error);
3560 if (mono_llvm_only) {
3561 g_assert (del->method);
3562 /* del->method_ptr might already be set to no_llvmonly_interp_method_pointer if the delegate was created from the interpreter */
3563 del->method_ptr = mini_llvmonly_load_method_delegate (del->method, FALSE, FALSE, &del->extra_arg, error);
3564 } else if (!del->method_ptr && !del->interp_method) {
3565 del->method_ptr = create_delegate_method_ptr (del->method, error);
3566 return_if_nok (error);
3570 char*
3571 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3573 int abs_offset;
3575 abs_offset = offset;
3576 if (abs_offset < 0)
3577 abs_offset = - abs_offset;
3578 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / TARGET_SIZEOF_VOID_P);
3581 gpointer
3582 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3584 gboolean is_virtual_generic, is_interface, load_imt_reg;
3585 int offset, idx;
3587 static guint8 **cache = NULL;
3588 static int cache_size = 0;
3590 if (!method)
3591 return NULL;
3593 if (MONO_TYPE_ISSTRUCT (sig->ret))
3594 return NULL;
3596 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3597 is_interface = mono_class_is_interface (method->klass);
3598 load_imt_reg = is_virtual_generic || is_interface;
3600 if (is_interface)
3601 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
3602 else
3603 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
3605 idx = (offset / TARGET_SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3606 g_assert (idx >= 0);
3608 /* Resize the cache to idx + 1 */
3609 if (cache_size < idx + 1) {
3610 mono_jit_lock ();
3611 if (cache_size < idx + 1) {
3612 guint8 **new_cache;
3613 int new_cache_size = idx + 1;
3615 new_cache = g_new0 (guint8*, new_cache_size);
3616 if (cache)
3617 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3618 g_free (cache);
3620 mono_memory_barrier ();
3621 cache = new_cache;
3622 cache_size = new_cache_size;
3624 mono_jit_unlock ();
3627 if (cache [idx])
3628 return cache [idx];
3630 /* FIXME Support more cases */
3631 if (mono_ee_features.use_aot_trampolines) {
3632 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3633 g_assert (cache [idx]);
3634 } else {
3635 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3637 return cache [idx];
3641 * mini_parse_debug_option:
3642 * @option: The option to parse.
3644 * Parses debug options for the mono runtime. The options are the same as for
3645 * the MONO_DEBUG environment variable.
3648 gboolean
3649 mini_parse_debug_option (const char *option)
3651 // Empty string is ok as consequence of appending ",foo"
3652 // without first checking for empty.
3653 if (*option == 0)
3654 return TRUE;
3656 if (!strcmp (option, "handle-sigint"))
3657 mini_debug_options.handle_sigint = TRUE;
3658 else if (!strcmp (option, "keep-delegates"))
3659 mini_debug_options.keep_delegates = TRUE;
3660 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3661 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3662 else if (!strcmp (option, "collect-pagefault-stats"))
3663 mini_debug_options.collect_pagefault_stats = TRUE;
3664 else if (!strcmp (option, "break-on-unverified"))
3665 mini_debug_options.break_on_unverified = TRUE;
3666 else if (!strcmp (option, "no-gdb-backtrace"))
3667 mini_debug_options.no_gdb_backtrace = TRUE;
3668 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3669 mini_debug_options.suspend_on_native_crash = TRUE;
3670 else if (!strcmp (option, "suspend-on-exception"))
3671 mini_debug_options.suspend_on_exception = TRUE;
3672 else if (!strcmp (option, "suspend-on-unhandled"))
3673 mini_debug_options.suspend_on_unhandled = TRUE;
3674 else if (!strcmp (option, "dont-free-domains"))
3675 mono_dont_free_domains = TRUE;
3676 else if (!strcmp (option, "dyn-runtime-invoke"))
3677 mini_debug_options.dyn_runtime_invoke = TRUE;
3678 else if (!strcmp (option, "gdb"))
3679 mini_debug_options.gdb = TRUE;
3680 else if (!strcmp (option, "lldb"))
3681 mini_debug_options.lldb = TRUE;
3682 else if (!strcmp (option, "llvm-disable-self-init"))
3683 mini_debug_options.llvm_disable_self_init = TRUE;
3684 else if (!strcmp (option, "explicit-null-checks"))
3685 mini_debug_options.explicit_null_checks = TRUE;
3686 else if (!strcmp (option, "gen-seq-points"))
3687 mini_debug_options.gen_sdb_seq_points = TRUE;
3688 else if (!strcmp (option, "gen-compact-seq-points"))
3689 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3690 else if (!strcmp (option, "no-compact-seq-points"))
3691 mini_debug_options.no_seq_points_compact_data = TRUE;
3692 else if (!strcmp (option, "single-imm-size"))
3693 mini_debug_options.single_imm_size = TRUE;
3694 else if (!strcmp (option, "init-stacks"))
3695 mini_debug_options.init_stacks = TRUE;
3696 else if (!strcmp (option, "casts"))
3697 mini_debug_options.better_cast_details = TRUE;
3698 else if (!strcmp (option, "soft-breakpoints"))
3699 mini_debug_options.soft_breakpoints = TRUE;
3700 else if (!strcmp (option, "check-pinvoke-callconv"))
3701 mini_debug_options.check_pinvoke_callconv = TRUE;
3702 else if (!strcmp (option, "use-fallback-tls"))
3703 mini_debug_options.use_fallback_tls = TRUE;
3704 else if (!strcmp (option, "debug-domain-unload"))
3705 mono_enable_debug_domain_unload (TRUE);
3706 else if (!strcmp (option, "partial-sharing"))
3707 mono_set_partial_sharing_supported (TRUE);
3708 else if (!strcmp (option, "align-small-structs"))
3709 mono_align_small_structs = TRUE;
3710 else if (!strcmp (option, "native-debugger-break"))
3711 mini_debug_options.native_debugger_break = TRUE;
3712 else if (!strcmp (option, "disable_omit_fp"))
3713 mini_debug_options.disable_omit_fp = TRUE;
3714 // This is an internal testing feature.
3715 // Every tail. encountered is required to be optimized.
3716 // It is asserted.
3717 else if (!strcmp (option, "test-tailcall-require"))
3718 mini_debug_options.test_tailcall_require = TRUE;
3719 else if (!strcmp (option, "verbose-gdb"))
3720 mini_debug_options.verbose_gdb = TRUE;
3721 else if (!strncmp (option, "thread-dump-dir=", 16))
3722 mono_set_thread_dump_dir(g_strdup(option + 16));
3723 else if (!strncmp (option, "aot-skip=", 9)) {
3724 mini_debug_options.aot_skip_set = TRUE;
3725 mini_debug_options.aot_skip = atoi (option + 9);
3726 } else
3727 return FALSE;
3729 return TRUE;
3732 static void
3733 mini_parse_debug_options (void)
3735 char *options = g_getenv ("MONO_DEBUG");
3736 gchar **args, **ptr;
3738 if (!options)
3739 return;
3741 args = g_strsplit (options, ",", -1);
3742 g_free (options);
3744 for (ptr = args; ptr && *ptr; ptr++) {
3745 const char *arg = *ptr;
3747 if (!mini_parse_debug_option (arg)) {
3748 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3749 // test-tailcall-require is also accepted but not documented.
3750 // empty string is also accepted and ignored as a consequence
3751 // of appending ",foo" without checking for empty.
3752 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");
3753 exit (1);
3757 g_strfreev (args);
3760 MonoDebugOptions *
3761 mini_get_debug_options (void)
3763 return &mini_debug_options;
3766 static gpointer
3767 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3769 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3770 gpointer* desc = NULL;
3772 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3773 return desc;
3774 #if defined(__mono_ppc64__)
3775 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3777 desc [0] = addr;
3778 desc [1] = NULL;
3779 desc [2] = NULL;
3780 # endif
3781 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3782 return desc;
3783 #else
3784 return addr;
3785 #endif
3788 static gpointer
3789 mini_get_addr_from_ftnptr (gpointer descr)
3791 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3792 return *(gpointer*)descr;
3793 #else
3794 return descr;
3795 #endif
3798 static void
3799 register_jit_stats (void)
3801 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3802 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3803 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3804 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3805 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
3806 mono_counters_register ("JIT/method_to_ir", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_method_to_ir);
3807 mono_counters_register ("JIT/liveness_handle_exception_clauses", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3808 mono_counters_register ("JIT/handle_out_of_line_bblock", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_out_of_line_bblock);
3809 mono_counters_register ("JIT/decompose_long_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_long_opts);
3810 mono_counters_register ("JIT/decompose_typechecks", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_typechecks);
3811 mono_counters_register ("JIT/local_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop);
3812 mono_counters_register ("JIT/local_emulate_ops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_emulate_ops);
3813 mono_counters_register ("JIT/optimize_branches", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches);
3814 mono_counters_register ("JIT/handle_global_vregs", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs);
3815 mono_counters_register ("JIT/local_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce);
3816 mono_counters_register ("JIT/local_alias_analysis", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_alias_analysis);
3817 mono_counters_register ("JIT/if_conversion", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_if_conversion);
3818 mono_counters_register ("JIT/bb_ordering", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_bb_ordering);
3819 mono_counters_register ("JIT/compile_dominator_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compile_dominator_info);
3820 mono_counters_register ("JIT/compute_natural_loops", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_compute_natural_loops);
3821 mono_counters_register ("JIT/insert_safepoints", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_insert_safepoints);
3822 mono_counters_register ("JIT/ssa_compute", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_compute);
3823 mono_counters_register ("JIT/ssa_cprop", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_cprop);
3824 mono_counters_register ("JIT/ssa_deadce", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_deadce);
3825 mono_counters_register ("JIT/perform_abc_removal", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_perform_abc_removal);
3826 mono_counters_register ("JIT/ssa_remove", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_ssa_remove);
3827 mono_counters_register ("JIT/local_cprop2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop2);
3828 mono_counters_register ("JIT/handle_global_vregs2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_handle_global_vregs2);
3829 mono_counters_register ("JIT/local_deadce2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce2);
3830 mono_counters_register ("JIT/optimize_branches2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_optimize_branches2);
3831 mono_counters_register ("JIT/decompose_vtype_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_vtype_opts);
3832 mono_counters_register ("JIT/decompose_array_access_opts", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_decompose_array_access_opts);
3833 mono_counters_register ("JIT/liveness_handle_exception_clauses2", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3834 mono_counters_register ("JIT/analyze_liveness", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_analyze_liveness);
3835 mono_counters_register ("JIT/linear_scan", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_linear_scan);
3836 mono_counters_register ("JIT/arch_allocate_vars", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_arch_allocate_vars);
3837 mono_counters_register ("JIT/spill_global_var", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_spill_global_vars);
3838 mono_counters_register ("JIT/local_cprop3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_cprop3);
3839 mono_counters_register ("JIT/local_deadce3", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_local_deadce3);
3840 mono_counters_register ("JIT/codegen", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_codegen);
3841 mono_counters_register ("JIT/create_jit_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_create_jit_info);
3842 mono_counters_register ("JIT/gc_create_gc_map", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_gc_create_gc_map);
3843 mono_counters_register ("JIT/save_seq_point_info", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_save_seq_point_info);
3844 mono_counters_register ("Total time spent JITting", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_jit_stats.jit_time);
3845 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3846 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3847 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3848 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3849 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3850 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3851 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3852 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3853 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3854 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3855 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3856 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3857 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3858 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3859 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3860 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3861 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3862 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3865 static void runtime_invoke_info_free (gpointer value);
3867 static gint
3868 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3870 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3871 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3873 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3876 static guint
3877 class_method_pair_hash (gconstpointer data)
3879 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3881 return (gsize)pair->klass ^ (gsize)pair->method;
3884 static void
3885 mini_create_jit_domain_info (MonoDomain *domain)
3887 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3889 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3890 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3891 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3892 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3893 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3894 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3895 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3896 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3897 mono_jit_code_hash_init (&info->interp_code_hash);
3899 domain->runtime_info = info;
3902 static void
3903 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3905 MonoJumpList *jlist = (MonoJumpList *)value;
3906 g_slist_free ((GSList*)jlist->list);
3909 static void
3910 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3912 GSList *list = (GSList *)value;
3913 g_slist_free (list);
3916 static void
3917 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3919 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3920 mono_code_manager_destroy (di->code_mp);
3921 g_free (di);
3924 static void
3925 runtime_invoke_info_free (gpointer value)
3927 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3929 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3930 if (info->dyn_call_info)
3931 mono_arch_dyn_call_free (info->dyn_call_info);
3932 #endif
3933 g_free (info);
3936 static void
3937 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3939 g_slist_free ((GSList*)value);
3942 static void
3943 mini_free_jit_domain_info (MonoDomain *domain)
3945 MonoJitDomainInfo *info = domain_jit_info (domain);
3947 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3948 g_hash_table_destroy (info->jump_target_hash);
3949 if (info->jump_target_got_slot_hash) {
3950 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3951 g_hash_table_destroy (info->jump_target_got_slot_hash);
3953 if (info->dynamic_code_hash) {
3954 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3955 g_hash_table_destroy (info->dynamic_code_hash);
3957 g_hash_table_destroy (info->method_code_hash);
3958 g_hash_table_destroy (info->jump_trampoline_hash);
3959 g_hash_table_destroy (info->jit_trampoline_hash);
3960 g_hash_table_destroy (info->delegate_trampoline_hash);
3961 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3962 g_hash_table_destroy (info->mrgctx_hash);
3963 g_hash_table_destroy (info->method_rgctx_hash);
3964 g_hash_table_destroy (info->interp_method_pointer_hash);
3965 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3966 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3967 g_hash_table_destroy (info->seq_points);
3968 g_hash_table_destroy (info->arch_seq_points);
3969 if (info->agent_info)
3970 mini_get_dbg_callbacks ()->free_domain_info (domain);
3971 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3972 if (info->llvm_jit_callees) {
3973 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3974 g_hash_table_destroy (info->llvm_jit_callees);
3976 mono_internal_hash_table_destroy (&info->interp_code_hash);
3977 #ifdef ENABLE_LLVM
3978 mono_llvm_free_domain_info (domain);
3979 #endif
3981 g_free (domain->runtime_info);
3982 domain->runtime_info = NULL;
3985 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3987 static void
3988 code_manager_chunk_new (void *chunk, int size)
3990 mono_arch_code_chunk_new (chunk, size);
3993 static void
3994 code_manager_chunk_destroy (void *chunk)
3996 mono_arch_code_chunk_destroy (chunk);
3999 #endif
4001 #ifdef ENABLE_LLVM
4002 static gboolean
4003 llvm_init_inner (void)
4005 if (!mono_llvm_load (NULL))
4006 return FALSE;
4008 mono_llvm_init ();
4009 return TRUE;
4011 #endif
4014 * mini_llvm_init:
4016 * Load and initialize LLVM support.
4017 * Return TRUE on success.
4019 gboolean
4020 mini_llvm_init (void)
4022 #ifdef ENABLE_LLVM
4023 static gboolean llvm_inited;
4024 static gboolean init_result;
4026 mono_loader_lock_if_inited ();
4027 if (!llvm_inited) {
4028 init_result = llvm_init_inner ();
4029 llvm_inited = TRUE;
4031 mono_loader_unlock_if_inited ();
4032 return init_result;
4033 #else
4034 return FALSE;
4035 #endif
4038 void
4039 mini_add_profiler_argument (const char *desc)
4041 if (!profile_options)
4042 profile_options = g_ptr_array_new ();
4044 g_ptr_array_add (profile_options, (gpointer) desc);
4048 static MonoEECallbacks interp_cbs = {0};
4050 void
4051 mini_install_interp_callbacks (MonoEECallbacks *cbs)
4053 memcpy (&interp_cbs, cbs, sizeof (MonoEECallbacks));
4056 MonoEECallbacks *
4057 mini_get_interp_callbacks (void)
4059 return &interp_cbs;
4062 static MonoDebuggerCallbacks dbg_cbs;
4064 void
4065 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4067 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4068 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4071 MonoDebuggerCallbacks*
4072 mini_get_dbg_callbacks (void)
4074 return &dbg_cbs;
4078 mono_ee_api_version (void)
4080 return MONO_EE_API_VERSION;
4083 void
4084 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4086 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4089 void
4090 mono_interp_to_native_trampoline (gpointer addr, gpointer ccontext)
4092 mini_get_interp_callbacks ()->to_native_trampoline (addr, ccontext);
4095 static gboolean
4096 mini_is_interpreter_enabled (void)
4098 return mono_use_interpreter;
4101 static const char*
4102 mono_get_runtime_build_version (void);
4104 MonoDomain *
4105 mini_init (const char *filename, const char *runtime_version)
4107 ERROR_DECL (error);
4108 MonoDomain *domain;
4109 MonoRuntimeCallbacks callbacks;
4110 MonoThreadInfoRuntimeCallbacks ticallbacks;
4111 MonoCodeManagerCallbacks code_manager_callbacks;
4113 MONO_VES_INIT_BEGIN ();
4115 CHECKED_MONO_INIT ();
4117 #if defined(__linux__)
4118 if (access ("/proc/self/maps", F_OK) != 0) {
4119 g_print ("Mono requires /proc to be mounted.\n");
4120 exit (1);
4122 #endif
4124 mono_interp_stub_init ();
4125 #ifndef DISABLE_INTERPRETER
4126 if (mono_use_interpreter)
4127 mono_ee_interp_init (mono_interp_opts_string);
4128 #endif
4130 mono_debugger_agent_stub_init ();
4131 #ifndef DISABLE_SDB
4132 mono_debugger_agent_init ();
4133 #endif
4135 if (sdb_options)
4136 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4138 mono_os_mutex_init_recursive (&jit_mutex);
4140 mono_cross_helpers_run ();
4142 mono_counters_init ();
4144 mini_jit_init ();
4146 mini_jit_init_job_control ();
4148 /* Happens when using the embedding interface */
4149 if (!default_opt_set)
4150 default_opt = mono_parse_default_optimizations (NULL);
4152 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4153 if (mono_aot_only)
4154 mono_set_generic_sharing_vt_supported (TRUE);
4155 #else
4156 if (mono_llvm_only)
4157 mono_set_generic_sharing_vt_supported (TRUE);
4158 #endif
4160 mono_tls_init_runtime_keys ();
4162 if (!global_codeman)
4163 global_codeman = mono_code_manager_new ();
4165 memset (&callbacks, 0, sizeof (callbacks));
4166 callbacks.create_ftnptr = mini_create_ftnptr;
4167 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4168 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4169 callbacks.get_runtime_build_version = mono_get_runtime_build_version;
4170 callbacks.set_cast_details = mono_set_cast_details;
4171 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4172 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4173 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4174 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4175 callbacks.imt_entry_inited = mini_imt_entry_inited;
4176 callbacks.init_delegate = mini_init_delegate;
4177 #define JIT_INVOKE_WORKS
4178 #ifdef JIT_INVOKE_WORKS
4179 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4180 #endif
4181 #define JIT_TRAMPOLINES_WORK
4182 #ifdef JIT_TRAMPOLINES_WORK
4183 callbacks.compile_method = mono_jit_compile_method;
4184 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4185 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4186 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4187 callbacks.free_method = mono_jit_free_method;
4188 #ifndef DISABLE_REMOTING
4189 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4190 #endif
4191 #endif
4192 #ifndef DISABLE_REMOTING
4193 if (mono_use_interpreter)
4194 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4195 #endif
4196 callbacks.is_interpreter_enabled = mini_is_interpreter_enabled;
4197 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4199 #ifndef DISABLE_CRASH_REPORTING
4200 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4201 #endif
4203 mono_install_callbacks (&callbacks);
4205 memset (&ticallbacks, 0, sizeof (ticallbacks));
4206 ticallbacks.setup_async_callback = mono_setup_async_callback;
4207 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
4208 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
4209 ticallbacks.thread_state_init = mono_thread_state_init;
4211 #ifndef HOST_WIN32
4212 mono_w32handle_init ();
4213 #endif
4215 mono_thread_info_runtime_init (&ticallbacks);
4217 if (g_hasenv ("MONO_DEBUG")) {
4218 mini_parse_debug_options ();
4221 mono_code_manager_init ();
4223 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
4224 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4225 code_manager_callbacks.chunk_new = code_manager_chunk_new;
4226 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
4227 #endif
4228 mono_code_manager_install_callbacks (&code_manager_callbacks);
4230 mono_hwcap_init ();
4232 mono_arch_cpu_init ();
4234 mono_arch_init ();
4236 mono_unwind_init ();
4238 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
4239 mono_lldb_init ("");
4240 mono_dont_free_domains = TRUE;
4243 #ifdef XDEBUG_ENABLED
4244 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4245 if (mono_xdebug) {
4246 mono_xdebug_init (mono_xdebug);
4247 g_free (mono_xdebug);
4248 /* So methods for multiple domains don't have the same address */
4249 mono_dont_free_domains = TRUE;
4250 mono_using_xdebug = TRUE;
4251 } else if (mini_get_debug_options ()->gdb) {
4252 mono_xdebug_init ((char*)"gdb");
4253 mono_dont_free_domains = TRUE;
4254 mono_using_xdebug = TRUE;
4256 #endif
4258 #ifdef ENABLE_LLVM
4259 if (mono_use_llvm) {
4260 if (!mono_llvm_load (NULL)) {
4261 mono_use_llvm = FALSE;
4262 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4265 if (mono_use_llvm)
4266 mono_llvm_init ();
4267 #endif
4269 mono_trampolines_init ();
4271 if (default_opt & MONO_OPT_AOT)
4272 mono_aot_init ();
4274 mini_get_dbg_callbacks ()->init ();
4276 #ifdef TARGET_WASM
4277 mono_wasm_debugger_init ();
4278 #endif
4280 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4281 mono_set_generic_sharing_supported (TRUE);
4282 #endif
4284 mono_thread_info_signals_init ();
4286 mono_init_native_crash_info ();
4288 #ifndef MONO_CROSS_COMPILE
4289 mono_runtime_install_handlers ();
4290 #endif
4291 mono_threads_install_cleanup (mini_thread_cleanup);
4293 #ifdef JIT_TRAMPOLINES_WORK
4294 mono_install_create_domain_hook (mini_create_jit_domain_info);
4295 mono_install_free_domain_hook (mini_free_jit_domain_info);
4296 #endif
4297 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4298 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4299 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4301 mono_profiler_state.context_enable = mini_profiler_context_enable;
4302 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4303 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4304 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4305 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4306 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4308 if (profile_options)
4309 for (guint i = 0; i < profile_options->len; i++)
4310 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4312 mono_profiler_started ();
4314 if (mini_debug_options.collect_pagefault_stats)
4315 mono_aot_set_make_unreadable (TRUE);
4317 if (runtime_version)
4318 domain = mono_init_version (filename, runtime_version);
4319 else
4320 domain = mono_init_from_assembly (filename, filename);
4322 if (mono_aot_only) {
4323 /* This helps catch code allocation requests */
4324 mono_code_manager_set_read_only (domain->code_mp);
4325 mono_marshal_use_aot_wrappers (TRUE);
4328 if (mono_llvm_only) {
4329 mono_install_imt_trampoline_builder (mini_llvmonly_get_imt_trampoline);
4330 mono_set_always_build_imt_trampolines (TRUE);
4331 } else if (mono_aot_only) {
4332 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4333 } else {
4334 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4337 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4338 mono_arch_finish_init ();
4340 /* This must come after mono_init () in the aot-only case */
4341 mono_exceptions_init ();
4343 /* This should come after mono_init () too */
4344 mini_gc_init ();
4346 mono_create_icall_signatures ();
4348 register_jit_stats ();
4350 #define JIT_CALLS_WORK
4351 #ifdef JIT_CALLS_WORK
4352 /* Needs to be called here since register_jit_icall depends on it */
4353 mono_marshal_init ();
4355 mono_arch_register_lowlevel_calls ();
4357 register_icalls ();
4359 mono_generic_sharing_init ();
4360 #endif
4362 #ifdef MONO_ARCH_SIMD_INTRINSICS
4363 mono_simd_intrinsics_init ();
4364 #endif
4366 mono_tasklets_init ();
4368 register_trampolines (domain);
4370 if (mono_compile_aot)
4372 * Avoid running managed code when AOT compiling, since the platform
4373 * might only support aot-only execution.
4375 mono_runtime_set_no_exec (TRUE);
4377 mono_mem_account_register_counters ();
4379 #define JIT_RUNTIME_WORKS
4380 #ifdef JIT_RUNTIME_WORKS
4381 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4382 mono_runtime_init_checked (domain, (MonoThreadStartCB)mono_thread_start_cb, mono_thread_attach_cb, error);
4383 mono_error_assert_ok (error);
4384 mono_thread_attach (domain);
4385 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4386 #endif
4388 if (mono_profiler_sampling_enabled ())
4389 mono_runtime_setup_stat_profiler ();
4391 MONO_PROFILER_RAISE (runtime_initialized, ());
4393 MONO_VES_INIT_END ();
4395 return domain;
4398 #ifdef MONO_ARCH_EMULATE_FREM
4399 // Wrapper to avoid taking address of overloaded function.
4400 static double
4401 mono_fmod (double a, double b)
4403 return fmod (a, b);
4405 #endif
4407 static void
4408 register_icalls (void)
4410 mono_add_internal_call_internal ("System.Diagnostics.StackFrame::get_frame_info",
4411 ves_icall_get_frame_info);
4412 mono_add_internal_call_internal ("System.Diagnostics.StackTrace::get_trace",
4413 ves_icall_get_trace);
4414 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_install_handlers",
4415 mono_runtime_install_handlers);
4416 mono_add_internal_call_internal ("Mono.Runtime::mono_runtime_cleanup_handlers",
4417 mono_runtime_cleanup_handlers);
4419 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4420 mono_add_internal_call_internal ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4421 mini_get_dbg_callbacks ()->unhandled_exception);
4422 #endif
4425 * It's important that we pass `TRUE` as the last argument here, as
4426 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4427 * *did* emit a wrapper, we'd be looking at infinite recursion since
4428 * the wrapper would call the icall which would call the wrapper and
4429 * so on.
4431 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", mono_icall_sig_void_ptr_ptr, TRUE);
4432 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", mono_icall_sig_void_ptr_ptr, TRUE);
4433 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", mono_icall_sig_void_ptr_ptr, TRUE);
4434 register_icall (mono_profiler_raise_exception_clause, "mono_profiler_raise_exception_clause", mono_icall_sig_void_ptr_int_int_object, TRUE);
4436 register_icall (mono_trace_enter_method, "mono_trace_enter_method", mono_icall_sig_void_ptr_ptr, TRUE);
4437 register_icall (mono_trace_leave_method, "mono_trace_leave_method", mono_icall_sig_void_ptr_ptr, TRUE);
4438 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", mono_icall_sig_ptr, TRUE);
4439 register_icall (mono_jit_set_domain, "mono_jit_set_domain", mono_icall_sig_void_ptr, TRUE);
4440 register_icall (mono_domain_get, "mono_domain_get", mono_icall_sig_ptr, TRUE);
4442 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", mono_icall_sig_void_object, TRUE);
4443 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", mono_icall_sig_void_object, TRUE);
4444 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", mono_icall_sig_void, TRUE);
4445 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
4446 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4447 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", mono_icall_sig_object, TRUE);
4448 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", mono_icall_sig_void_int, TRUE);
4449 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) && defined(HAVE_UNWIND_H)
4450 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4452 // FIXME: This is broken
4453 #ifndef TARGET_WASM
4454 register_icall (mono_debug_personality, "mono_debug_personality", mono_icall_sig_int_int_int_ptr_ptr_ptr, TRUE);
4455 #endif
4456 #endif
4458 if (!mono_llvm_only) {
4459 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", mono_icall_sig_void_object, TRUE);
4460 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", mono_icall_sig_void_object, TRUE);
4461 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", mono_icall_sig_void_ptr, TRUE);
4463 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", mono_icall_sig_object, FALSE);
4464 register_icall (ves_icall_thread_finish_async_abort, "ves_icall_thread_finish_async_abort", mono_icall_sig_void, FALSE);
4465 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", mono_icall_sig_object, FALSE);
4466 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", mono_icall_sig_object, FALSE);
4468 register_icall (mono_threads_state_poll, "mono_threads_state_poll", mono_icall_sig_void, FALSE);
4470 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4471 register_opcode_emulation (OP_LMUL, __emul_lmul, mono_icall_sig_long_long_long, mono_llmult, "mono_llmult", FALSE);
4472 register_opcode_emulation (OP_LDIV, __emul_ldiv, mono_icall_sig_long_long_long, mono_lldiv, "mono_lldiv", FALSE);
4473 register_opcode_emulation (OP_LDIV_UN, __emul_ldiv_un, mono_icall_sig_long_long_long, mono_lldiv_un, "mono_lldiv_un", FALSE);
4474 register_opcode_emulation (OP_LREM, __emul_lrem, mono_icall_sig_long_long_long, mono_llrem, "mono_llrem", FALSE);
4475 register_opcode_emulation (OP_LREM_UN, __emul_lrem_un, mono_icall_sig_long_long_long, mono_llrem_un, "mono_llrem_un", FALSE);
4476 #endif
4477 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4478 register_opcode_emulation (OP_LMUL_OVF_UN, __emul_lmul_ovf_un, mono_icall_sig_long_long_long, mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4479 register_opcode_emulation (OP_LMUL_OVF, __emul_lmul_ovf, mono_icall_sig_long_long_long, mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4480 #endif
4482 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4483 register_opcode_emulation (OP_LSHL, __emul_lshl, mono_icall_sig_long_long_int32, mono_lshl, "mono_lshl", TRUE);
4484 register_opcode_emulation (OP_LSHR, __emul_lshr, mono_icall_sig_long_long_int32, mono_lshr, "mono_lshr", TRUE);
4485 register_opcode_emulation (OP_LSHR_UN, __emul_lshr_un, mono_icall_sig_long_long_int32, mono_lshr_un, "mono_lshr_un", TRUE);
4486 #endif
4488 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4489 register_opcode_emulation (OP_IDIV, __emul_op_idiv, mono_icall_sig_int32_int32_int32, mono_idiv, "mono_idiv", FALSE);
4490 register_opcode_emulation (OP_IDIV_UN, __emul_op_idiv_un, mono_icall_sig_int32_int32_int32, mono_idiv_un, "mono_idiv_un", FALSE);
4491 register_opcode_emulation (OP_IREM, __emul_op_irem, mono_icall_sig_int32_int32_int32, mono_irem, "mono_irem", FALSE);
4492 register_opcode_emulation (OP_IREM_UN, __emul_op_irem_un, mono_icall_sig_int32_int32_int32, mono_irem_un, "mono_irem_un", FALSE);
4493 #endif
4495 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4496 register_opcode_emulation (OP_IMUL, __emul_op_imul, mono_icall_sig_int32_int32_int32, mono_imul, "mono_imul", TRUE);
4497 #endif
4499 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4500 register_opcode_emulation (OP_IMUL_OVF, __emul_op_imul_ovf, mono_icall_sig_int32_int32_int32, mono_imul_ovf, "mono_imul_ovf", FALSE);
4501 register_opcode_emulation (OP_IMUL_OVF_UN, __emul_op_imul_ovf_un, mono_icall_sig_int32_int32_int32, mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4502 #endif
4504 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4505 register_opcode_emulation (OP_FDIV, __emul_fdiv, mono_icall_sig_double_double_double, mono_fdiv, "mono_fdiv", FALSE);
4506 #endif
4508 register_opcode_emulation (OP_FCONV_TO_U8, __emul_fconv_to_u8, mono_icall_sig_ulong_double, mono_fconv_u8_2, "mono_fconv_u8_2", FALSE);
4509 register_opcode_emulation (OP_RCONV_TO_U8, __emul_rconv_to_u8, mono_icall_sig_ulong_float, mono_rconv_u8, "mono_rconv_u8", FALSE);
4510 register_opcode_emulation (OP_FCONV_TO_U4, __emul_fconv_to_u4, mono_icall_sig_uint32_double, mono_fconv_u4_2, "mono_fconv_u4_2", FALSE);
4511 register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4512 register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4513 register_opcode_emulation (OP_RCONV_TO_OVF_I8, __emul_rconv_to_ovf_i8, mono_icall_sig_long_float, mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4514 register_opcode_emulation (OP_RCONV_TO_OVF_U8, __emul_rconv_to_ovf_u8, mono_icall_sig_ulong_float, mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4517 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4518 register_opcode_emulation (OP_FCONV_TO_I8, __emul_fconv_to_i8, mono_icall_sig_long_double, mono_fconv_i8, "mono_fconv_i8", FALSE);
4519 register_opcode_emulation (OP_RCONV_TO_I8, __emul_rconv_to_i8, mono_icall_sig_long_float, mono_rconv_i8, "mono_rconv_i8", FALSE);
4520 #endif
4522 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4523 register_opcode_emulation (OP_ICONV_TO_R_UN, __emul_iconv_to_r_un, mono_icall_sig_double_int32, mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);
4524 #endif
4525 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4526 register_opcode_emulation (OP_LCONV_TO_R8, __emul_lconv_to_r8, mono_icall_sig_double_long, mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4527 #endif
4528 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4529 register_opcode_emulation (OP_LCONV_TO_R4, __emul_lconv_to_r4, mono_icall_sig_float_long, mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4530 #endif
4531 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4532 register_opcode_emulation (OP_LCONV_TO_R_UN, __emul_lconv_to_r8_un, mono_icall_sig_double_long, mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
4533 #endif
4534 #ifdef MONO_ARCH_EMULATE_FREM
4535 register_opcode_emulation (OP_FREM, __emul_frem, mono_icall_sig_double_double_double, mono_fmod, "fmod", FALSE);
4536 register_opcode_emulation (OP_RREM, __emul_rrem, mono_icall_sig_float_float_float, fmodf, "fmodf", FALSE);
4537 #endif
4539 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4540 if (mono_arch_is_soft_float ()) {
4541 register_opcode_emulation (OP_FSUB, __emul_fsub, mono_icall_sig_double_double_double, mono_fsub, "mono_fsub", FALSE);
4542 register_opcode_emulation (OP_FADD, __emul_fadd, mono_icall_sig_double_double_double, mono_fadd, "mono_fadd", FALSE);
4543 register_opcode_emulation (OP_FMUL, __emul_fmul, mono_icall_sig_double_double_double, mono_fmul, "mono_fmul", FALSE);
4544 register_opcode_emulation (OP_FNEG, __emul_fneg, mono_icall_sig_double_double, mono_fneg, "mono_fneg", FALSE);
4545 register_opcode_emulation (OP_ICONV_TO_R8, __emul_iconv_to_r8, mono_icall_sig_double_int32, mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4546 register_opcode_emulation (OP_ICONV_TO_R4, __emul_iconv_to_r4, mono_icall_sig_double_int32, mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4547 register_opcode_emulation (OP_FCONV_TO_R4, __emul_fconv_to_r4, mono_icall_sig_double_double, mono_fconv_r4, "mono_fconv_r4", FALSE);
4548 register_opcode_emulation (OP_FCONV_TO_I1, __emul_fconv_to_i1, mono_icall_sig_int8_double, mono_fconv_i1, "mono_fconv_i1", FALSE);
4549 register_opcode_emulation (OP_FCONV_TO_I2, __emul_fconv_to_i2, mono_icall_sig_int16_double, mono_fconv_i2, "mono_fconv_i2", FALSE);
4550 register_opcode_emulation (OP_FCONV_TO_I4, __emul_fconv_to_i4, mono_icall_sig_int32_double, mono_fconv_i4, "mono_fconv_i4", FALSE);
4551 register_opcode_emulation (OP_FCONV_TO_U1, __emul_fconv_to_u1, mono_icall_sig_uint8_double, mono_fconv_u1, "mono_fconv_u1", FALSE);
4552 register_opcode_emulation (OP_FCONV_TO_U2, __emul_fconv_to_u2, mono_icall_sig_uint16_double, mono_fconv_u2, "mono_fconv_u2", FALSE);
4554 #if TARGET_SIZEOF_VOID_P == 4
4555 register_opcode_emulation (OP_FCONV_TO_I, __emul_fconv_to_i, mono_icall_sig_int32_double, mono_fconv_i4, "mono_fconv_i4", FALSE);
4556 #endif
4558 register_opcode_emulation (OP_FBEQ, __emul_fcmp_eq, mono_icall_sig_uint32_double_double, mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4559 register_opcode_emulation (OP_FBLT, __emul_fcmp_lt, mono_icall_sig_uint32_double_double, mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4560 register_opcode_emulation (OP_FBGT, __emul_fcmp_gt, mono_icall_sig_uint32_double_double, mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4561 register_opcode_emulation (OP_FBLE, __emul_fcmp_le, mono_icall_sig_uint32_double_double, mono_fcmp_le, "mono_fcmp_le", FALSE);
4562 register_opcode_emulation (OP_FBGE, __emul_fcmp_ge, mono_icall_sig_uint32_double_double, mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4563 register_opcode_emulation (OP_FBNE_UN, __emul_fcmp_ne_un, mono_icall_sig_uint32_double_double, mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4564 register_opcode_emulation (OP_FBLT_UN, __emul_fcmp_lt_un, mono_icall_sig_uint32_double_double, mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4565 register_opcode_emulation (OP_FBGT_UN, __emul_fcmp_gt_un, mono_icall_sig_uint32_double_double, mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4566 register_opcode_emulation (OP_FBLE_UN, __emul_fcmp_le_un, mono_icall_sig_uint32_double_double, mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4567 register_opcode_emulation (OP_FBGE_UN, __emul_fcmp_ge_un, mono_icall_sig_uint32_double_double, mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4569 register_opcode_emulation (OP_FCEQ, __emul_fcmp_ceq, mono_icall_sig_uint32_double_double, mono_fceq, "mono_fceq", FALSE);
4570 register_opcode_emulation (OP_FCGT, __emul_fcmp_cgt, mono_icall_sig_uint32_double_double, mono_fcgt, "mono_fcgt", FALSE);
4571 register_opcode_emulation (OP_FCGT_UN, __emul_fcmp_cgt_un, mono_icall_sig_uint32_double_double, mono_fcgt_un, "mono_fcgt_un", FALSE);
4572 register_opcode_emulation (OP_FCLT, __emul_fcmp_clt, mono_icall_sig_uint32_double_double, mono_fclt, "mono_fclt", FALSE);
4573 register_opcode_emulation (OP_FCLT_UN, __emul_fcmp_clt_un, mono_icall_sig_uint32_double_double, mono_fclt_un, "mono_fclt_un", FALSE);
4575 register_icall (mono_fload_r4, "mono_fload_r4", mono_icall_sig_double_ptr, FALSE);
4576 register_icall (mono_fstore_r4, "mono_fstore_r4", mono_icall_sig_void_double_ptr, FALSE);
4577 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", mono_icall_sig_uint32_double, FALSE);
4578 register_icall (mono_isfinite_double, "mono_isfinite_double", mono_icall_sig_int32_double, FALSE);
4580 #endif
4581 register_icall (mono_ckfinite, "mono_ckfinite", mono_icall_sig_double_double, FALSE);
4583 #ifdef COMPRESSED_INTERFACE_BITMAP
4584 register_icall (mono_class_interface_match, "mono_class_interface_match", mono_icall_sig_uint32_ptr_int32, TRUE);
4585 #endif
4587 #if SIZEOF_REGISTER == 4
4588 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_uint32_double, mono_fconv_u4, "mono_fconv_u4", TRUE);
4589 #else
4590 register_opcode_emulation (OP_FCONV_TO_U, __emul_fconv_to_u, mono_icall_sig_ulong_double, mono_fconv_u8, "mono_fconv_u8", TRUE);
4591 #endif
4593 /* other jit icalls */
4594 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", mono_icall_sig_void_object_object_ptr, FALSE);
4595 register_icall (ves_icall_mono_delegate_ctor_interp, "ves_icall_mono_delegate_ctor_interp", mono_icall_sig_void_object_object_ptr, FALSE);
4596 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4597 mono_icall_sig_ptr_ptr_ptr, FALSE);
4598 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4599 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4600 mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4601 register_icall (mono_get_special_static_data, "mono_get_special_static_data", mono_icall_sig_ptr_int, FALSE);
4602 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", mono_icall_sig_object_ptr_ptr_int32, FALSE);
4603 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", mono_icall_sig_void_object_object, FALSE);
4604 register_icall (ves_icall_object_new, "ves_icall_object_new", mono_icall_sig_object_ptr_ptr, FALSE);
4605 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", mono_icall_sig_object_ptr, FALSE);
4606 register_icall (ves_icall_array_new, "ves_icall_array_new", mono_icall_sig_object_ptr_ptr_int32, FALSE);
4607 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", mono_icall_sig_object_ptr_int32, FALSE);
4608 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", mono_icall_sig_void_ptr, FALSE);
4609 register_icall (mono_ldftn, "mono_ldftn", mono_icall_sig_ptr_ptr, FALSE);
4610 register_icall (mono_ldvirtfn, "mono_ldvirtfn", mono_icall_sig_ptr_object_ptr, FALSE);
4611 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", mono_icall_sig_ptr_object_ptr, FALSE);
4612 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", mono_icall_sig_ptr_object_ptr_ptr, FALSE);
4613 register_icall (mono_helper_ldstr, "mono_helper_ldstr", mono_icall_sig_object_ptr_int, FALSE);
4614 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", mono_icall_sig_object_int, FALSE);
4615 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", mono_icall_sig_object_int, FALSE);
4616 register_icall (mono_value_copy_internal, "mono_value_copy_internal", mono_icall_sig_void_ptr_ptr_ptr, FALSE);
4617 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", mono_icall_sig_object_object_ptr, FALSE);
4618 register_icall (mono_break, "mono_break", NULL, TRUE);
4619 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", mono_icall_sig_object_int, TRUE);
4620 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", mono_icall_sig_object_int_object, TRUE);
4621 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", mono_icall_sig_object_int_object_object, TRUE);
4622 register_icall (mono_array_new_1, "mono_array_new_1", mono_icall_sig_object_ptr_int, FALSE);
4623 register_icall (mono_array_new_2, "mono_array_new_2", mono_icall_sig_object_ptr_int_int, FALSE);
4624 register_icall (mono_array_new_3, "mono_array_new_3", mono_icall_sig_object_ptr_int_int_int, FALSE);
4625 register_icall (mono_array_new_4, "mono_array_new_4", mono_icall_sig_object_ptr_int_int_int_int, FALSE);
4626 register_icall (mono_array_new_n_icall, "mono_array_new_n_icall", mono_icall_sig_object_ptr_int_ptr, FALSE);
4627 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", mono_icall_sig_ptr_ptr_ptr_ptr, FALSE);
4628 register_icall (mono_resume_unwind, "mono_resume_unwind", mono_icall_sig_void_ptr, TRUE);
4629 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", mono_icall_sig_object_ptr_ptr_ptr_ptr_ptr, FALSE);
4630 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", mono_icall_sig_void_ptr_ptr_ptr, TRUE);
4632 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4633 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", mono_icall_sig_void_ptr_ptr_int);
4635 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", mono_icall_sig_object_object_ptr_ptr, FALSE);
4636 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", mono_icall_sig_object_object_ptr_ptr, FALSE);
4637 register_icall (mono_generic_class_init, "mono_generic_class_init", mono_icall_sig_void_ptr, FALSE);
4638 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", mono_icall_sig_ptr_ptr_int, FALSE);
4639 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", mono_icall_sig_ptr_ptr_int, FALSE);
4641 register_dyn_icall (mini_get_dbg_callbacks ()->user_break, "mono_debugger_agent_user_break", mono_icall_sig_void, FALSE);
4643 register_icall (mini_llvm_init_method, "mini_llvm_init_method", mono_icall_sig_void_ptr_int, TRUE);
4644 register_icall (mini_llvm_init_gshared_method_this, "mini_llvm_init_gshared_method_this", mono_icall_sig_void_ptr_int_object, TRUE);
4645 register_icall (mini_llvm_init_gshared_method_mrgctx, "mini_llvm_init_gshared_method_mrgctx", mono_icall_sig_void_ptr_int_ptr, TRUE);
4646 register_icall (mini_llvm_init_gshared_method_vtable, "mini_llvm_init_gshared_method_vtable", mono_icall_sig_void_ptr_int_ptr, TRUE);
4648 register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, "mini_llvmonly_resolve_iface_call_gsharedvt", mono_icall_sig_ptr_object_int_ptr_ptr);
4649 register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, "mini_llvmonly_resolve_vcall_gsharedvt", mono_icall_sig_ptr_object_int_ptr_ptr);
4650 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_call, "mini_llvmonly_resolve_generic_virtual_call", mono_icall_sig_ptr_ptr_int_ptr);
4651 register_icall_no_wrapper (mini_llvmonly_resolve_generic_virtual_iface_call, "mini_llvmonly_resolve_generic_virtual_iface_call", mono_icall_sig_ptr_ptr_int_ptr);
4652 /* This needs a wrapper so it can have a preserveall cconv */
4653 register_icall (mini_llvmonly_init_vtable_slot, "mini_llvmonly_init_vtable_slot", mono_icall_sig_ptr_ptr_int, FALSE);
4654 register_icall (mini_llvmonly_init_delegate, "mini_llvmonly_init_delegate", mono_icall_sig_void_object, TRUE);
4655 register_icall (mini_llvmonly_init_delegate_virtual, "mini_llvmonly_init_delegate_virtual", mono_icall_sig_void_object_object_ptr, TRUE);
4656 register_icall (mini_llvmonly_throw_nullref_exception, "mini_llvmonly_throw_nullref_exception", mono_icall_sig_void, TRUE);
4658 register_icall (mono_get_assembly_object, "mono_get_assembly_object", mono_icall_sig_object_ptr, TRUE);
4659 register_icall (mono_get_method_object, "mono_get_method_object", mono_icall_sig_object_ptr, TRUE);
4660 register_icall (mono_throw_method_access, "mono_throw_method_access", mono_icall_sig_void_ptr_ptr, FALSE);
4661 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", mono_icall_sig_void);
4663 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", mono_icall_sig_int32_obj);
4664 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", mono_icall_sig_void_obj_ptr);
4665 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", mono_icall_sig_int_obj);
4666 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", mono_icall_sig_int_obj_ptr);
4668 #ifdef TARGET_IOS
4669 register_icall (pthread_getspecific, "pthread_getspecific", mono_icall_sig_ptr_ptr, TRUE);
4670 #endif
4671 /* Register tls icalls */
4672 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", mono_icall_sig_ptr);
4673 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", mono_icall_sig_ptr);
4674 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", mono_icall_sig_ptr);
4675 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", mono_icall_sig_ptr);
4676 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", mono_icall_sig_ptr);
4677 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", mono_icall_sig_void_ptr);
4678 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", mono_icall_sig_void_ptr);
4679 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", mono_icall_sig_void_ptr);
4680 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", mono_icall_sig_void_ptr);
4681 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", mono_icall_sig_void_ptr);
4683 register_icall_no_wrapper (mono_interp_entry_from_trampoline, "mono_interp_entry_from_trampoline", mono_icall_sig_void_ptr_ptr);
4684 register_icall_no_wrapper (mono_interp_to_native_trampoline, "mono_interp_to_native_trampoline", mono_icall_sig_void_ptr_ptr);
4686 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4687 mono_arch_register_icall ();
4688 #endif
4691 MonoJitStats mono_jit_stats = {0};
4694 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4695 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4697 MONO_NO_SANITIZE_THREAD
4698 static void
4699 print_jit_stats (void)
4701 if (mono_jit_stats.enabled) {
4702 g_print ("Mono Jit statistics\n");
4703 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4704 mono_jit_stats.max_ratio_method);
4705 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4706 mono_jit_stats.biggest_method);
4708 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4709 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4710 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4711 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4712 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4713 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4714 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4715 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4717 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4718 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4719 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4721 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4722 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4723 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4724 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4726 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4727 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4728 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4729 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4730 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4731 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4732 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4733 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4735 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4736 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4737 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4739 g_free (mono_jit_stats.max_ratio_method);
4740 mono_jit_stats.max_ratio_method = NULL;
4741 g_free (mono_jit_stats.biggest_method);
4742 mono_jit_stats.biggest_method = NULL;
4746 #ifdef DISABLE_CLEANUP
4747 void
4748 mini_cleanup (MonoDomain *domain)
4751 #else
4752 void
4753 mini_cleanup (MonoDomain *domain)
4755 if (mono_profiler_sampling_enabled ())
4756 mono_runtime_shutdown_stat_profiler ();
4758 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4760 #ifndef DISABLE_COM
4761 mono_cominterop_release_all_rcws ();
4762 #endif
4764 #ifndef MONO_CROSS_COMPILE
4766 * mono_domain_finalize () needs to be called early since it needs the
4767 * execution engine still fully working (it may invoke managed finalizers).
4769 mono_domain_finalize (domain, 2000);
4770 #endif
4772 /* This accesses metadata so needs to be called before runtime shutdown */
4773 print_jit_stats ();
4775 #ifndef MONO_CROSS_COMPILE
4776 mono_runtime_cleanup (domain);
4777 #endif
4779 mono_threadpool_cleanup ();
4781 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4783 mono_profiler_cleanup ();
4785 if (profile_options)
4786 g_ptr_array_free (profile_options, TRUE);
4788 free_jit_tls_data (mono_tls_get_jit_tls ());
4790 mono_icall_cleanup ();
4792 mono_runtime_cleanup_handlers ();
4794 #ifndef MONO_CROSS_COMPILE
4795 mono_domain_free (domain, TRUE);
4796 #endif
4798 #ifdef ENABLE_LLVM
4799 if (mono_use_llvm)
4800 mono_llvm_cleanup ();
4801 #endif
4803 mono_aot_cleanup ();
4805 mono_trampolines_cleanup ();
4807 mono_unwind_cleanup ();
4809 mono_code_manager_destroy (global_codeman);
4810 g_free (vtable_trampolines);
4812 mini_jit_cleanup ();
4814 mono_tramp_info_cleanup ();
4816 mono_arch_cleanup ();
4818 mono_generic_sharing_cleanup ();
4820 mono_cleanup_native_crash_info ();
4822 mono_cleanup ();
4824 mono_trace_cleanup ();
4826 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4828 if (mono_inject_async_exc_method)
4829 mono_method_desc_free (mono_inject_async_exc_method);
4831 mono_tls_free_keys ();
4833 mono_os_mutex_destroy (&jit_mutex);
4835 mono_code_manager_cleanup ();
4837 #ifndef HOST_WIN32
4838 mono_w32handle_cleanup ();
4839 #endif
4841 #endif
4843 void
4844 mono_set_defaults (int verbose_level, guint32 opts)
4846 mini_verbose = verbose_level;
4847 mono_set_optimizations (opts);
4850 void
4851 mono_disable_optimizations (guint32 opts)
4853 default_opt &= ~opts;
4856 void
4857 mono_set_optimizations (guint32 opts)
4859 default_opt = opts;
4860 default_opt_set = TRUE;
4861 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4862 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4863 #else
4864 if (mono_llvm_only)
4865 mono_set_generic_sharing_vt_supported (TRUE);
4866 #endif
4869 void
4870 mono_set_verbose_level (guint32 level)
4872 mini_verbose = level;
4875 static const char*
4876 mono_get_runtime_build_version (void)
4878 return FULL_VERSION;
4882 * mono_get_runtime_build_info:
4883 * The returned string is owned by the caller. The returned string
4884 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4885 * \returns the runtime version + build date in string format.
4887 char*
4888 mono_get_runtime_build_info (void)
4890 if (mono_build_date)
4891 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4892 else
4893 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4896 static void
4897 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4899 GHashTable *assemblies = (GHashTable*)user_data;
4900 MonoImage *image = mono_assembly_get_image_internal (ass);
4901 MonoMethod *method, *invoke;
4902 int i, count = 0;
4904 if (g_hash_table_lookup (assemblies, ass))
4905 return;
4907 g_hash_table_insert (assemblies, ass, ass);
4909 if (mini_verbose > 0)
4910 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4912 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4913 ERROR_DECL (error);
4915 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
4916 if (!method) {
4917 mono_error_cleanup (error); /* FIXME don't swallow the error */
4918 continue;
4920 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4921 continue;
4922 if (method->is_generic || mono_class_is_gtd (method->klass))
4923 continue;
4925 count++;
4926 if (mini_verbose > 1) {
4927 char * desc = mono_method_full_name (method, TRUE);
4928 g_print ("Compiling %d %s\n", count, desc);
4929 g_free (desc);
4931 mono_compile_method_checked (method, error);
4932 if (!is_ok (error)) {
4933 mono_error_cleanup (error); /* FIXME don't swallow the error */
4934 continue;
4936 if (strcmp (method->name, "Finalize") == 0) {
4937 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4938 mono_compile_method_checked (invoke, error);
4939 mono_error_assert_ok (error);
4941 #ifndef DISABLE_REMOTING
4942 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature_internal (method)->hasthis) {
4943 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
4944 mono_error_assert_ok (error);
4945 mono_compile_method_checked (invoke, error);
4946 mono_error_assert_ok (error);
4948 #endif
4951 /* Load and precompile referenced assemblies as well */
4952 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4953 mono_assembly_load_reference (image, i);
4954 if (image->references [i])
4955 mono_precompile_assembly (image->references [i], assemblies);
4959 void mono_precompile_assemblies ()
4961 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4963 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4965 g_hash_table_destroy (assemblies);
4969 * Used by LLVM.
4970 * Have to export this for AOT.
4972 void
4973 mono_personality (void)
4975 /* Not used */
4976 g_assert_not_reached ();
4979 static MonoBreakPolicy
4980 always_insert_breakpoint (MonoMethod *method)
4982 return MONO_BREAK_POLICY_ALWAYS;
4985 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4988 * mono_set_break_policy:
4989 * \param policy_callback the new callback function
4991 * Allow embedders to decide whether to actually obey breakpoint instructions
4992 * (both break IL instructions and \c Debugger.Break method calls), for example
4993 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4994 * untrusted or semi-trusted code.
4996 * \p policy_callback will be called every time a break point instruction needs to
4997 * be inserted with the method argument being the method that calls \c Debugger.Break
4998 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4999 * if it wants the breakpoint to not be effective in the given method.
5000 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5002 void
5003 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5005 if (policy_callback)
5006 break_policy_func = policy_callback;
5007 else
5008 break_policy_func = always_insert_breakpoint;
5011 gboolean
5012 mini_should_insert_breakpoint (MonoMethod *method)
5014 switch (break_policy_func (method)) {
5015 case MONO_BREAK_POLICY_ALWAYS:
5016 return TRUE;
5017 case MONO_BREAK_POLICY_NEVER:
5018 return FALSE;
5019 case MONO_BREAK_POLICY_ON_DBG:
5020 g_warning ("mdb no longer supported");
5021 return FALSE;
5022 default:
5023 g_warning ("Incorrect value returned from break policy callback");
5024 return FALSE;
5028 // Custom handlers currently only implemented by Windows.
5029 #ifndef HOST_WIN32
5030 gboolean
5031 mono_runtime_install_custom_handlers (const char *handlers)
5033 return FALSE;
5036 void
5037 mono_runtime_install_custom_handlers_usage (void)
5039 fprintf (stdout,
5040 "Custom Handlers:\n"
5041 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5042 " separated list of available handlers to install.\n"
5043 "\n"
5044 "No handlers supported on current platform.\n");
5046 #endif /* HOST_WIN32 */