[mini] return gracefully from compile_special if a method can not be compiled
[mono-project.git] / mono / mini / mini-runtime.c
blob70a3493001858c82e80c63350fd9688008da662d
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/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/metadata/profiler-private.h>
43 #include <mono/metadata/mono-config.h>
44 #include <mono/metadata/environment.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/threads-types.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/runtime.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/utils/mono-math.h>
54 #include <mono/utils/mono-compiler.h>
55 #include <mono/utils/mono-counters.h>
56 #include <mono/utils/mono-error-internals.h>
57 #include <mono/utils/mono-logger-internals.h>
58 #include <mono/utils/mono-mmap.h>
59 #include <mono/utils/mono-path.h>
60 #include <mono/utils/mono-tls.h>
61 #include <mono/utils/mono-hwcap.h>
62 #include <mono/utils/dtrace.h>
63 #include <mono/utils/mono-signal-handler.h>
64 #include <mono/utils/mono-threads.h>
65 #include <mono/utils/mono-threads-coop.h>
66 #include <mono/utils/checked-build.h>
67 #include <mono/utils/mono-compiler.h>
68 #include <mono/utils/mono-proclib.h>
69 #include <mono/metadata/w32handle.h>
70 #include <mono/metadata/threadpool.h>
72 #include "mini.h"
73 #include "seq-points.h"
74 #include "tasklets.h"
75 #include <string.h>
76 #include <ctype.h>
77 #include "trace.h"
78 #include "version.h"
79 #include "aot-compiler.h"
80 #include "aot-runtime.h"
82 #include "jit-icalls.h"
84 #include "mini-gc.h"
85 #include "mini-llvm.h"
86 #include "debugger-agent.h"
87 #include "lldb.h"
88 #include "mini-runtime.h"
89 #include "interp/interp.h"
91 #ifdef MONO_ARCH_LLVM_SUPPORTED
92 #ifdef ENABLE_LLVM
93 #include "mini-llvm-cpp.h"
94 #include "llvm-jit.h"
95 #endif
96 #endif
98 static guint32 default_opt = 0;
99 static gboolean default_opt_set = FALSE;
101 gboolean mono_compile_aot = FALSE;
102 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
103 gboolean mono_aot_only = FALSE;
104 /* Same as mono_aot_only, but only LLVM compiled code is used, no trampolines */
105 gboolean mono_llvm_only = FALSE;
106 MonoAotMode mono_aot_mode = MONO_AOT_MODE_NONE;
107 MonoEEFeatures mono_ee_features;
109 const char *mono_build_date;
110 gboolean mono_do_signal_chaining;
111 gboolean mono_do_crash_chaining;
112 int mini_verbose = 0;
115 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
116 * it can load AOT code compiled by LLVM.
118 gboolean mono_use_llvm = FALSE;
120 gboolean mono_use_interpreter = FALSE;
121 const char *mono_interp_opts_string = NULL;
123 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
124 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
125 static mono_mutex_t jit_mutex;
127 static MonoCodeManager *global_codeman;
129 MonoDebugOptions mini_debug_options;
130 char *sdb_options;
132 #ifdef VALGRIND_JIT_REGISTER_MAP
133 int valgrind_register;
134 #endif
135 GList* mono_aot_paths;
137 static GPtrArray *profile_options;
139 static GSList *tramp_infos;
140 GSList *mono_interp_only_classes;
142 static void register_icalls (void);
144 gboolean
145 mono_running_on_valgrind (void)
147 #ifndef HOST_WIN32
148 if (RUNNING_ON_VALGRIND){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register = TRUE;
151 #endif
152 return TRUE;
153 } else
154 #endif
155 return FALSE;
158 typedef struct {
159 void *ip;
160 MonoMethod *method;
161 } FindTrampUserData;
163 static void
164 find_tramp (gpointer key, gpointer value, gpointer user_data)
166 FindTrampUserData *ud = (FindTrampUserData*)user_data;
168 if (value == ud->ip)
169 ud->method = (MonoMethod*)key;
172 /* debug function */
173 G_GNUC_UNUSED static char*
174 get_method_from_ip (void *ip)
176 MonoJitInfo *ji;
177 MonoMethod *method;
178 char *method_name;
179 char *res;
180 MonoDomain *domain = mono_domain_get ();
181 MonoDebugSourceLocation *location;
182 FindTrampUserData user_data;
184 if (!domain)
185 domain = mono_get_root_domain ();
187 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
188 if (!ji) {
189 user_data.ip = ip;
190 user_data.method = NULL;
191 mono_domain_lock (domain);
192 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
193 mono_domain_unlock (domain);
194 if (user_data.method) {
195 char *mname = mono_method_full_name (user_data.method, TRUE);
196 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
197 g_free (mname);
198 return res;
200 else
201 return NULL;
202 } else if (ji->is_trampoline) {
203 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
204 return res;
207 method = jinfo_get_method (ji);
208 method_name = mono_method_full_name (method, TRUE);
209 /* FIXME: unused ? */
210 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
212 res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
214 mono_debug_free_source_location (location);
215 g_free (method_name);
217 return res;
221 * mono_pmip:
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
232 G_GNUC_UNUSED char *
233 mono_pmip (void *ip)
235 return get_method_from_ip (ip);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
249 MONO_ATTR_USED void
250 mono_print_method_from_ip (void *ip)
252 MonoJitInfo *ji;
253 char *method;
254 MonoDebugSourceLocation *source;
255 MonoDomain *domain = mono_domain_get ();
256 MonoDomain *target_domain = mono_domain_get ();
257 FindTrampUserData user_data;
258 MonoGenericSharingContext*gsctx;
259 const char *shared_type;
261 if (!domain)
262 domain = mono_get_root_domain ();
263 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
264 if (ji && ji->is_trampoline) {
265 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
268 return;
271 if (!ji) {
272 user_data.ip = ip;
273 user_data.method = NULL;
274 mono_domain_lock (domain);
275 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
276 mono_domain_unlock (domain);
278 if (user_data.method) {
279 char *mname = mono_method_full_name (user_data.method, TRUE);
280 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
281 g_free (mname);
282 return;
285 g_print ("No method at %p\n", ip);
286 fflush (stdout);
287 return;
289 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
290 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
292 gsctx = mono_jit_info_get_generic_sharing_context (ji);
293 shared_type = "";
294 if (gsctx) {
295 if (gsctx->is_gsharedvt)
296 shared_type = "gsharedvt ";
297 else
298 shared_type = "gshared ";
301 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);
303 if (source)
304 g_print ("%s:%d\n", source->source_file, source->row);
305 fflush (stdout);
307 mono_debug_free_source_location (source);
308 g_free (method);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
319 MonoMethod *cmethod;
321 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
322 return FALSE;
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller->domain_neutral && !callee->domain_neutral)
329 return FALSE;
331 cmethod = jinfo_get_method (caller);
332 if ((cmethod->klass == mono_defaults.appdomain_class) &&
333 (strstr (cmethod->name, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
335 return FALSE;
338 return TRUE;
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size)
348 void *ptr;
350 if (mono_aot_only)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman) {
354 /* This can happen during startup */
355 global_codeman = mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman, size);
358 else {
359 mono_jit_lock ();
360 ptr = mono_code_manager_reserve (global_codeman, size);
361 mono_jit_unlock ();
362 return ptr;
366 /* The callback shouldn't take any locks */
367 void
368 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
370 mono_jit_lock ();
371 mono_code_manager_foreach (global_codeman, func, user_data);
372 mono_jit_unlock ();
376 * mono_create_unwind_op:
378 * Create an unwind op with the given parameters.
380 MonoUnwindOp*
381 mono_create_unwind_op (int when, int tag, int reg, int val)
383 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
385 op->op = tag;
386 op->reg = reg;
387 op->val = val;
388 op->when = when;
390 return op;
393 MonoJumpInfoToken *
394 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
396 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
397 res->image = image;
398 res->token = token;
399 res->has_context = context != NULL;
400 if (context)
401 memcpy (&res->context, context, sizeof (MonoGenericContext));
403 return res;
406 MonoJumpInfoToken *
407 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
409 return mono_jump_info_token_new2 (mp, image, token, NULL);
413 * mono_tramp_info_create:
415 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
416 * of JI, and UNWIND_OPS.
418 MonoTrampInfo*
419 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
421 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
423 info->name = g_strdup ((char*)name);
424 info->code = code;
425 info->code_size = code_size;
426 info->ji = ji;
427 info->unwind_ops = unwind_ops;
429 return info;
432 void
433 mono_tramp_info_free (MonoTrampInfo *info)
435 g_free (info->name);
437 // FIXME: ji
438 mono_free_unwind_info (info->unwind_ops);
439 if (info->owns_uw_info)
440 g_free (info->uw_info);
441 g_free (info);
444 static void
445 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
447 MonoJitInfo *ji;
449 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
450 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
451 ji->d.tramp_info = info;
452 ji->is_trampoline = TRUE;
454 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
456 mono_jit_info_table_add (domain, ji);
460 * mono_tramp_info_register:
462 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
463 * INFO can be NULL.
464 * Frees INFO.
466 static void
467 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
469 MonoTrampInfo *copy;
471 if (!info)
472 return;
474 if (!domain)
475 domain = mono_get_root_domain ();
477 if (domain)
478 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
479 else
480 copy = g_new0 (MonoTrampInfo, 1);
482 copy->code = info->code;
483 copy->code_size = info->code_size;
484 copy->name = g_strdup (info->name);
486 if (info->unwind_ops) {
487 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
488 copy->owns_uw_info = TRUE;
489 if (domain) {
490 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
491 guint8 *temp = copy->uw_info;
492 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
493 memcpy (copy->uw_info, temp, copy->uw_info_len);
494 g_free (temp);
496 } else {
497 /* Trampolines from aot have the unwind ops already encoded */
498 copy->uw_info = info->uw_info;
499 copy->uw_info_len = info->uw_info_len;
502 mono_save_trampoline_xdebug_info (info);
503 mono_lldb_save_trampoline_info (info);
505 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
506 if (!aot)
507 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
508 #endif
510 if (!domain) {
511 /* If no root domain has been created yet, postpone the registration. */
512 mono_jit_lock ();
513 tramp_infos = g_slist_prepend (tramp_infos, copy);
514 mono_jit_unlock ();
515 } else if (copy->uw_info) {
516 /* Only register trampolines that have unwind infos */
517 register_trampoline_jit_info (domain, copy);
520 if (mono_jit_map_is_enabled ())
521 mono_emit_jit_tramp (info->code, info->code_size, info->name);
523 mono_tramp_info_free (info);
526 void
527 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
529 mono_tramp_info_register_internal (info, domain, FALSE);
532 void
533 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
535 mono_tramp_info_register_internal (info, domain, TRUE);
538 static void
539 mono_tramp_info_cleanup (void)
541 GSList *l;
543 for (l = tramp_infos; l; l = l->next) {
544 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
546 mono_tramp_info_free (info);
548 g_slist_free (tramp_infos);
551 /* Register trampolines created before the root domain was created in the jit info tables */
552 static void
553 register_trampolines (MonoDomain *domain)
555 GSList *l;
557 for (l = tramp_infos; l; l = l->next) {
558 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
560 register_trampoline_jit_info (domain, info);
564 G_GNUC_UNUSED static void
565 break_count (void)
570 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
571 * Set a breakpoint in break_count () to break the last time <x> is done.
573 G_GNUC_UNUSED gboolean
574 mono_debug_count (void)
576 static int count = 0, int_val = 0;
577 static gboolean inited, has_value = FALSE;
579 count ++;
581 if (!inited) {
582 char *value = g_getenv ("COUNT");
583 if (value) {
584 int_val = atoi (value);
585 g_free (value);
586 has_value = TRUE;
588 inited = TRUE;
591 if (!has_value)
592 return TRUE;
594 if (count == int_val)
595 break_count ();
597 if (count > int_val)
598 return FALSE;
600 return TRUE;
603 gconstpointer
604 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
606 ERROR_DECL (error);
607 char *name;
608 MonoMethod *wrapper;
609 gconstpointer trampoline;
610 MonoDomain *domain = mono_get_root_domain ();
611 gboolean check_exc = TRUE;
613 if (callinfo->wrapper)
614 return callinfo->wrapper;
616 if (callinfo->trampoline)
617 return callinfo->trampoline;
619 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
620 /* This icall is used to check for exceptions, so don't check in the wrapper */
621 check_exc = FALSE;
623 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
624 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
625 g_free (name);
627 if (do_compile) {
628 trampoline = mono_compile_method_checked (wrapper, error);
629 mono_error_assert_ok (error);
630 } else {
632 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
633 mono_error_assert_ok (error);
634 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
637 mono_loader_lock ();
638 if (!callinfo->trampoline) {
639 mono_register_jit_icall_wrapper (callinfo, trampoline);
640 callinfo->trampoline = trampoline;
642 mono_loader_unlock ();
644 return callinfo->trampoline;
647 gconstpointer
648 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
650 return mono_icall_get_wrapper_full (callinfo, FALSE);
653 static MonoJitDynamicMethodInfo*
654 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
656 MonoJitDynamicMethodInfo *res;
658 if (domain_jit_info (domain)->dynamic_code_hash)
659 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
660 else
661 res = NULL;
662 return res;
665 static void
666 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_wrapper)
668 #ifndef DISABLE_JIT
669 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_wrapper);
670 #else
671 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
673 g_assert (!sig->hasthis);
674 g_assert (sig->param_count < 3);
676 mono_register_jit_icall_full (func, name, sig, no_wrapper, symbol);
677 #endif
681 * For JIT icalls implemented in C.
682 * NAME should be the same as the name of the C function whose address is FUNC.
683 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
684 * can't throw exceptions.
686 static void
687 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
689 MonoMethodSignature *sig;
691 if (sigstr)
692 sig = mono_create_icall_signature (sigstr);
693 else
694 sig = NULL;
696 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, avoid_wrapper ? name : NULL);
699 static void
700 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
702 MonoMethodSignature *sig;
704 if (sigstr)
705 sig = mono_create_icall_signature (sigstr);
706 else
707 sig = NULL;
709 mono_register_jit_icall_full (func, name, sig, TRUE, name);
712 static void
713 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
715 MonoMethodSignature *sig;
717 if (sigstr)
718 sig = mono_create_icall_signature (sigstr);
719 else
720 sig = NULL;
722 mono_register_jit_icall_full (func, name, sig, FALSE, NULL);
725 static void
726 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
728 MonoMethodSignature *sig;
730 if (sigstr)
731 sig = mono_create_icall_signature (sigstr);
732 else
733 sig = NULL;
735 mono_register_jit_icall (func, name, sig, save);
738 MonoLMF *
739 mono_get_lmf (void)
741 MonoJitTlsData *jit_tls;
743 if ((jit_tls = mono_tls_get_jit_tls ()))
744 return jit_tls->lmf;
746 * We do not assert here because this function can be called from
747 * mini-gc.c on a thread that has not executed any managed code, yet
748 * (the thread object allocation can trigger a collection).
750 return NULL;
753 MonoLMF **
754 mono_get_lmf_addr (void)
756 return (MonoLMF **)mono_tls_get_lmf_addr ();
759 void
760 mono_set_lmf (MonoLMF *lmf)
762 (*mono_get_lmf_addr ()) = lmf;
765 MonoJitTlsData*
766 mono_get_jit_tls (void)
768 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
771 static void
772 mono_set_jit_tls (MonoJitTlsData *jit_tls)
774 MonoThreadInfo *info;
776 mono_tls_set_jit_tls (jit_tls);
778 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
779 info = mono_thread_info_current ();
780 if (info)
781 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
784 static void
785 mono_set_lmf_addr (gpointer lmf_addr)
787 MonoThreadInfo *info;
789 mono_tls_set_lmf_addr (lmf_addr);
791 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
792 info = mono_thread_info_current ();
793 if (info)
794 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
798 * mono_push_lmf:
800 * Push an MonoLMFExt frame on the LMF stack.
802 void
803 mono_push_lmf (MonoLMFExt *ext)
805 MonoLMF **lmf_addr;
807 lmf_addr = mono_get_lmf_addr ();
809 ext->lmf.previous_lmf = *lmf_addr;
810 /* Mark that this is a MonoLMFExt */
811 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
813 mono_set_lmf ((MonoLMF*)ext);
817 * mono_pop_lmf:
819 * Pop the last frame from the LMF stack.
821 void
822 mono_pop_lmf (MonoLMF *lmf)
824 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
828 * mono_jit_thread_attach:
830 * Called by Xamarin.Mac and other products. Attach thread to runtime if
831 * needed and switch to @domain.
833 * @return the original domain which needs to be restored, or NULL.
835 MonoDomain*
836 mono_jit_thread_attach (MonoDomain *domain)
838 MonoDomain *orig;
839 gboolean attached;
841 if (!domain) {
842 /* Happens when called from AOTed code which is only used in the root domain. */
843 domain = mono_get_root_domain ();
846 g_assert (domain);
848 attached = mono_tls_get_jit_tls () != NULL;
850 if (!attached) {
851 mono_thread_attach (domain);
853 // #678164
854 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
857 orig = mono_domain_get ();
858 if (orig != domain)
859 mono_domain_set (domain, TRUE);
861 return orig != domain ? orig : NULL;
865 * mono_jit_set_domain:
867 * Set domain to @domain if @domain is not null
869 void
870 mono_jit_set_domain (MonoDomain *domain)
872 g_assert (!mono_threads_is_blocking_transition_enabled ());
874 if (domain)
875 mono_domain_set (domain, TRUE);
879 * mono_thread_abort:
880 * \param obj exception object
881 * Abort the thread, print exception information and stack trace
883 static void
884 mono_thread_abort (MonoObject *obj)
886 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
888 /* handle_remove should be eventually called for this thread, too
889 g_free (jit_tls);*/
891 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
892 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
893 ((obj->vtable->klass) == mono_class_get_appdomain_unloaded_exception_class () &&
894 mono_thread_info_current ()->runtime_thread)) {
895 mono_thread_exit ();
896 } else {
897 mono_invoke_unhandled_exception_hook (obj);
901 static void*
902 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
904 MonoJitTlsData *jit_tls;
905 MonoLMF *lmf;
907 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
908 if (jit_tls)
909 return jit_tls;
911 jit_tls = g_new0 (MonoJitTlsData, 1);
913 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
914 jit_tls->end_of_stack = stack_start;
916 mono_set_jit_tls (jit_tls);
918 lmf = g_new0 (MonoLMF, 1);
919 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
921 jit_tls->first_lmf = lmf;
923 mono_set_lmf_addr (&jit_tls->lmf);
925 jit_tls->lmf = lmf;
927 #ifdef MONO_ARCH_HAVE_TLS_INIT
928 mono_arch_tls_init ();
929 #endif
931 mono_setup_altstack (jit_tls);
933 return jit_tls;
936 static void
937 free_jit_tls_data (MonoJitTlsData *jit_tls)
939 mono_arch_free_jit_tls_data (jit_tls);
940 mono_free_altstack (jit_tls);
942 g_free (jit_tls->first_lmf);
943 g_free (jit_tls->interp_context);
944 g_free (jit_tls);
947 static void
948 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
950 MonoThreadInfo *thread;
951 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
952 thread = mono_thread_info_current_unchecked ();
953 if (thread)
954 thread->jit_data = jit_tls;
956 mono_arch_cpu_init ();
959 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
961 static void
962 mono_thread_abort_dummy (MonoObject *obj)
964 if (mono_thread_attach_aborted_cb)
965 mono_thread_attach_aborted_cb (obj);
966 else
967 mono_thread_abort (obj);
970 static void
971 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
973 MonoThreadInfo *thread;
974 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
975 thread = mono_thread_info_current_unchecked ();
976 if (thread)
977 thread->jit_data = jit_tls;
979 mono_arch_cpu_init ();
982 static void
983 mini_thread_cleanup (MonoNativeThreadId tid)
985 MonoJitTlsData *jit_tls = NULL;
986 MonoThreadInfo *info;
988 info = mono_thread_info_current_unchecked ();
990 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
991 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
992 * not a trivial thing.
994 * The current offender is mono_thread_manage which cleanup threads from the outside.
996 if (info && mono_thread_info_get_tid (info) == tid) {
997 jit_tls = (MonoJitTlsData *)info->jit_data;
998 info->jit_data = NULL;
1000 mono_set_jit_tls (NULL);
1002 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1003 if (mono_get_lmf ()) {
1004 mono_set_lmf (NULL);
1005 mono_set_lmf_addr (NULL);
1007 } else {
1008 info = mono_thread_info_lookup (tid);
1009 if (info) {
1010 jit_tls = (MonoJitTlsData *)info->jit_data;
1011 info->jit_data = NULL;
1013 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1016 if (jit_tls)
1017 free_jit_tls_data (jit_tls);
1020 MonoJumpInfo *
1021 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1023 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1025 ji->ip.i = ip;
1026 ji->type = type;
1027 ji->data.target = target;
1028 ji->next = list;
1030 return ji;
1033 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1035 static const char* const patch_info_str[] = {
1036 #define PATCH_INFO(a,b) "" #a,
1037 #include "patch-info.h"
1038 #undef PATCH_INFO
1041 const char*
1042 mono_ji_type_to_string (MonoJumpInfoType type)
1044 return patch_info_str [type];
1047 void
1048 mono_print_ji (const MonoJumpInfo *ji)
1050 switch (ji->type) {
1051 case MONO_PATCH_INFO_RGCTX_FETCH: {
1052 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1054 printf ("[RGCTX_FETCH ");
1055 mono_print_ji (entry->data);
1056 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1057 break;
1059 case MONO_PATCH_INFO_METHODCONST: {
1060 char *s = mono_method_full_name (ji->data.method, TRUE);
1061 printf ("[METHODCONST - %s]", s);
1062 g_free (s);
1063 break;
1065 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1066 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1067 break;
1069 default:
1070 printf ("[%s]", patch_info_str [ji->type]);
1071 break;
1075 #else
1077 const char*
1078 mono_ji_type_to_string (MonoJumpInfoType type)
1080 return "";
1083 void
1084 mono_print_ji (const MonoJumpInfo *ji)
1088 #endif
1091 * mono_patch_info_dup_mp:
1093 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1095 MonoJumpInfo*
1096 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1098 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1099 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1101 switch (patch_info->type) {
1102 case MONO_PATCH_INFO_RVA:
1103 case MONO_PATCH_INFO_LDSTR:
1104 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1105 case MONO_PATCH_INFO_LDTOKEN:
1106 case MONO_PATCH_INFO_DECLSEC:
1107 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1108 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1109 break;
1110 case MONO_PATCH_INFO_SWITCH:
1111 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1112 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1113 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1114 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1115 break;
1116 case MONO_PATCH_INFO_RGCTX_FETCH:
1117 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1118 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1119 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1120 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1121 break;
1122 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1123 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1124 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1125 break;
1126 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1127 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1128 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1129 break;
1130 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1131 MonoGSharedVtMethodInfo *info;
1132 MonoGSharedVtMethodInfo *oinfo;
1133 int i;
1135 oinfo = patch_info->data.gsharedvt_method;
1136 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1137 res->data.gsharedvt_method = info;
1138 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1139 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1140 for (i = 0; i < oinfo->num_entries; ++i) {
1141 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1142 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1144 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1146 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1147 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1148 break;
1150 case MONO_PATCH_INFO_VIRT_METHOD: {
1151 MonoJumpInfoVirtMethod *info;
1152 MonoJumpInfoVirtMethod *oinfo;
1154 oinfo = patch_info->data.virt_method;
1155 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1156 res->data.virt_method = info;
1157 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1158 break;
1160 default:
1161 break;
1164 return res;
1167 guint
1168 mono_patch_info_hash (gconstpointer data)
1170 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1172 switch (ji->type) {
1173 case MONO_PATCH_INFO_RVA:
1174 case MONO_PATCH_INFO_LDSTR:
1175 case MONO_PATCH_INFO_LDTOKEN:
1176 case MONO_PATCH_INFO_DECLSEC:
1177 return (ji->type << 8) | ji->data.token->token;
1178 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1179 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1180 case MONO_PATCH_INFO_INTERNAL_METHOD:
1181 return (ji->type << 8) | g_str_hash (ji->data.name);
1182 case MONO_PATCH_INFO_VTABLE:
1183 case MONO_PATCH_INFO_CLASS:
1184 case MONO_PATCH_INFO_IID:
1185 case MONO_PATCH_INFO_ADJUSTED_IID:
1186 case MONO_PATCH_INFO_METHODCONST:
1187 case MONO_PATCH_INFO_METHOD:
1188 case MONO_PATCH_INFO_METHOD_JUMP:
1189 case MONO_PATCH_INFO_IMAGE:
1190 case MONO_PATCH_INFO_ICALL_ADDR:
1191 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1192 case MONO_PATCH_INFO_FIELD:
1193 case MONO_PATCH_INFO_SFLDA:
1194 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1195 case MONO_PATCH_INFO_METHOD_RGCTX:
1196 case MONO_PATCH_INFO_SIGNATURE:
1197 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1198 case MONO_PATCH_INFO_AOT_JIT_INFO:
1199 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1200 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1201 return (ji->type << 8) | (gssize)ji->data.target;
1202 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1203 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1204 case MONO_PATCH_INFO_RGCTX_FETCH:
1205 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1206 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1208 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1210 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1211 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1212 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1213 case MONO_PATCH_INFO_GC_NURSERY_START:
1214 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1215 case MONO_PATCH_INFO_GOT_OFFSET:
1216 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1217 case MONO_PATCH_INFO_AOT_MODULE:
1218 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1219 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1220 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
1221 return (ji->type << 8);
1222 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1223 return (ji->type << 8) | (ji->data.index);
1224 case MONO_PATCH_INFO_SWITCH:
1225 return (ji->type << 8) | ji->data.table->table_size;
1226 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1227 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1228 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1229 /* Hash on the selector name */
1230 return g_str_hash (ji->data.target);
1231 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1232 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1233 case MONO_PATCH_INFO_LDSTR_LIT:
1234 return g_str_hash (ji->data.target);
1235 case MONO_PATCH_INFO_VIRT_METHOD: {
1236 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1238 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1240 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1241 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1242 return (ji->type << 8) | g_str_hash (ji->data.target);
1243 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1244 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1245 default:
1246 printf ("info type: %d\n", ji->type);
1247 mono_print_ji (ji); printf ("\n");
1248 g_assert_not_reached ();
1249 return 0;
1254 * mono_patch_info_equal:
1256 * This might fail to recognize equivalent patches, i.e. floats, so its only
1257 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1258 * in AOT.
1260 gint
1261 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1263 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1264 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1266 if (ji1->type != ji2->type)
1267 return 0;
1269 switch (ji1->type) {
1270 case MONO_PATCH_INFO_RVA:
1271 case MONO_PATCH_INFO_LDSTR:
1272 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1273 case MONO_PATCH_INFO_LDTOKEN:
1274 case MONO_PATCH_INFO_DECLSEC:
1275 if ((ji1->data.token->image != ji2->data.token->image) ||
1276 (ji1->data.token->token != ji2->data.token->token) ||
1277 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1278 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1279 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1280 return 0;
1281 break;
1282 case MONO_PATCH_INFO_INTERNAL_METHOD:
1283 return g_str_equal (ji1->data.name, ji2->data.name);
1284 case MONO_PATCH_INFO_RGCTX_FETCH:
1285 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1286 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1287 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1289 return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
1291 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1292 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1293 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1295 return c1->sig == c2->sig && c1->method == c2->method;
1297 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1298 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1299 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1300 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;
1301 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1302 return ji1->data.index == ji2->data.index;
1303 case MONO_PATCH_INFO_VIRT_METHOD:
1304 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1305 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1306 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1307 if (ji1->data.target == ji2->data.target)
1308 return 1;
1309 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1310 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1311 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1312 default:
1313 if (ji1->data.target != ji2->data.target)
1314 return 0;
1315 break;
1318 return 1;
1321 gpointer
1322 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1324 unsigned char *ip = patch_info->ip.i + code;
1325 gconstpointer target = NULL;
1327 error_init (error);
1329 switch (patch_info->type) {
1330 case MONO_PATCH_INFO_BB:
1332 * FIXME: This could be hit for methods without a prolog. Should use -1
1333 * but too much code depends on a 0 initial value.
1335 //g_assert (patch_info->data.bb->native_offset);
1336 target = patch_info->data.bb->native_offset + code;
1337 break;
1338 case MONO_PATCH_INFO_ABS:
1339 target = patch_info->data.target;
1340 break;
1341 case MONO_PATCH_INFO_LABEL:
1342 target = patch_info->data.inst->inst_c0 + code;
1343 break;
1344 case MONO_PATCH_INFO_IP:
1345 target = ip;
1346 break;
1347 case MONO_PATCH_INFO_METHOD_REL:
1348 target = code + patch_info->data.offset;
1349 break;
1350 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1351 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1352 if (!mi) {
1353 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1354 g_assert_not_reached ();
1356 target = mono_icall_get_wrapper (mi);
1357 break;
1359 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1360 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1361 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1362 if (!mi) {
1363 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1364 g_assert_not_reached ();
1366 target = mi->func;
1367 break;
1369 case MONO_PATCH_INFO_METHOD_JUMP:
1370 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1371 if (!mono_error_ok (error))
1372 return NULL;
1373 break;
1374 case MONO_PATCH_INFO_METHOD:
1375 if (patch_info->data.method == method) {
1376 target = code;
1377 } else {
1378 /* get the trampoline to the method from the domain */
1379 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1380 if (!mono_error_ok (error))
1381 return NULL;
1383 break;
1384 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1385 gpointer code_slot;
1387 mono_domain_lock (domain);
1388 if (!domain_jit_info (domain)->method_code_hash)
1389 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1390 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1391 if (!code_slot) {
1392 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1393 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1395 mono_domain_unlock (domain);
1396 target = code_slot;
1397 break;
1399 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1400 g_assert (mono_threads_are_safepoints_enabled ());
1401 target = (gpointer)&mono_polling_required;
1402 break;
1403 case MONO_PATCH_INFO_SWITCH: {
1404 gpointer *jump_table;
1405 int i;
1406 if (method && method->dynamic) {
1407 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1408 } else {
1409 if (mono_aot_only) {
1410 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1411 } else {
1412 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1416 for (i = 0; i < patch_info->data.table->table_size; i++) {
1417 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1420 target = jump_table;
1421 break;
1423 case MONO_PATCH_INFO_METHODCONST:
1424 case MONO_PATCH_INFO_CLASS:
1425 case MONO_PATCH_INFO_IMAGE:
1426 case MONO_PATCH_INFO_FIELD:
1427 case MONO_PATCH_INFO_SIGNATURE:
1428 case MONO_PATCH_INFO_AOT_MODULE:
1429 target = patch_info->data.target;
1430 break;
1431 case MONO_PATCH_INFO_IID:
1432 mono_class_init (patch_info->data.klass);
1433 target = GUINT_TO_POINTER (m_class_get_interface_id (patch_info->data.klass));
1434 break;
1435 case MONO_PATCH_INFO_ADJUSTED_IID:
1436 mono_class_init (patch_info->data.klass);
1437 target = GUINT_TO_POINTER ((guint32)(-((m_class_get_interface_id (patch_info->data.klass) + 1) * SIZEOF_VOID_P)));
1438 break;
1439 case MONO_PATCH_INFO_VTABLE:
1440 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1441 mono_error_assert_ok (error);
1442 break;
1443 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1444 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1446 if (del_tramp->is_virtual)
1447 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1448 else
1449 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1450 break;
1452 case MONO_PATCH_INFO_SFLDA: {
1453 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1454 mono_error_assert_ok (error);
1456 if (mono_class_field_is_special_static (patch_info->data.field)) {
1457 gpointer addr = NULL;
1459 mono_domain_lock (domain);
1460 if (domain->special_static_fields)
1461 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1462 mono_domain_unlock (domain);
1463 g_assert (addr);
1464 return addr;
1467 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1468 /* Done by the generated code */
1470 else {
1471 if (run_cctors) {
1472 if (!mono_runtime_class_init_full (vtable, error)) {
1473 return NULL;
1477 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1478 break;
1480 case MONO_PATCH_INFO_RVA: {
1481 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1482 guint32 rva;
1484 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1485 target = mono_image_rva_map (patch_info->data.token->image, rva);
1486 break;
1488 case MONO_PATCH_INFO_R4:
1489 case MONO_PATCH_INFO_R8:
1490 target = patch_info->data.target;
1491 break;
1492 case MONO_PATCH_INFO_EXC_NAME:
1493 target = patch_info->data.name;
1494 break;
1495 case MONO_PATCH_INFO_LDSTR:
1496 target =
1497 mono_ldstr_checked (domain, patch_info->data.token->image,
1498 mono_metadata_token_index (patch_info->data.token->token), error);
1499 break;
1500 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1501 gpointer handle;
1502 MonoClass *handle_class;
1504 handle = mono_ldtoken_checked (patch_info->data.token->image,
1505 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1506 if (!mono_error_ok (error))
1507 return NULL;
1508 mono_class_init (handle_class);
1509 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1511 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1512 if (!mono_error_ok (error))
1513 return NULL;
1514 break;
1516 case MONO_PATCH_INFO_LDTOKEN: {
1517 gpointer handle;
1518 MonoClass *handle_class;
1520 handle = mono_ldtoken_checked (patch_info->data.token->image,
1521 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1522 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1523 mono_class_init (handle_class);
1525 target = handle;
1526 break;
1528 case MONO_PATCH_INFO_DECLSEC:
1529 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1530 break;
1531 case MONO_PATCH_INFO_ICALL_ADDR:
1532 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1533 /* run_cctors == 0 -> AOT */
1534 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1535 const char *exc_class;
1536 const char *exc_arg;
1538 if (run_cctors) {
1539 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1540 if (!target) {
1541 if (mono_aot_only) {
1542 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1543 return NULL;
1545 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));
1547 } else {
1548 target = NULL;
1550 } else {
1551 target = mono_lookup_internal_call (patch_info->data.method);
1553 if (!target && run_cctors)
1554 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1556 break;
1557 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1558 target = mono_thread_interruption_request_flag ();
1559 break;
1560 case MONO_PATCH_INFO_METHOD_RGCTX:
1561 target = mini_method_get_rgctx (patch_info->data.method);
1562 break;
1563 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1564 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1566 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1567 break;
1569 case MONO_PATCH_INFO_BB_OVF:
1570 case MONO_PATCH_INFO_EXC_OVF:
1571 case MONO_PATCH_INFO_GOT_OFFSET:
1572 case MONO_PATCH_INFO_NONE:
1573 break;
1574 case MONO_PATCH_INFO_RGCTX_FETCH: {
1575 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1577 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1578 break;
1580 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1581 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1582 if (!run_cctors)
1583 /* AOT, not needed */
1584 target = NULL;
1585 else
1586 target = mono_arch_get_seq_point_info (domain, code);
1587 break;
1588 #endif
1589 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1590 int card_table_shift_bits;
1591 gpointer card_table_mask;
1593 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1594 break;
1596 case MONO_PATCH_INFO_GC_NURSERY_START: {
1597 int shift_bits;
1598 size_t size;
1600 target = mono_gc_get_nursery (&shift_bits, &size);
1601 break;
1603 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1604 int shift_bits;
1605 size_t size;
1607 mono_gc_get_nursery (&shift_bits, &size);
1609 target = (gpointer)(mgreg_t)shift_bits;
1610 break;
1612 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1613 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1614 break;
1616 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1617 target = NULL;
1618 break;
1620 case MONO_PATCH_INFO_LDSTR_LIT: {
1621 int len;
1622 char *s;
1624 len = strlen ((const char *)patch_info->data.target);
1625 s = (char *)mono_domain_alloc0 (domain, len + 1);
1626 memcpy (s, patch_info->data.target, len);
1627 target = s;
1629 break;
1631 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1632 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1633 break;
1634 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1635 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1636 break;
1637 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1638 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1639 break;
1640 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1641 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1642 g_assert (mi);
1643 target = mi->func;
1644 break;
1646 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1647 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1648 break;
1650 case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT: {
1651 target = (gpointer) &mono_profiler_state.exception_clause_count;
1652 break;
1654 default:
1655 g_assert_not_reached ();
1658 return (gpointer)target;
1662 * mini_register_jump_site:
1664 * Register IP as a jump/tailcall site which calls METHOD.
1665 * This is needed because common_call_trampoline () cannot patch
1666 * the call site because the caller ip is not available for jumps.
1668 void
1669 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1671 MonoJumpList *jlist;
1673 MonoMethod *shared_method = mini_method_to_shared (method);
1674 method = shared_method ? shared_method : method;
1676 mono_domain_lock (domain);
1677 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1678 if (!jlist) {
1679 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1680 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1682 jlist->list = g_slist_prepend (jlist->list, ip);
1683 mono_domain_unlock (domain);
1687 * mini_patch_jump_sites:
1689 * Patch jump/tailcall sites calling METHOD so the jump to ADDR.
1691 void
1692 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1694 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1696 if (!hash)
1697 return;
1699 MonoJumpInfo patch_info;
1700 MonoJumpList *jlist;
1701 GSList *tmp;
1703 /* The caller/callee might use different instantiations */
1704 MonoMethod *shared_method = mini_method_to_shared (method);
1705 method = shared_method ? shared_method : method;
1707 mono_domain_lock (domain);
1708 jlist = (MonoJumpList *)g_hash_table_lookup (hash, method);
1709 if (jlist)
1710 g_hash_table_remove (hash, method);
1711 mono_domain_unlock (domain);
1712 if (jlist) {
1713 patch_info.next = NULL;
1714 patch_info.ip.i = 0;
1715 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
1716 patch_info.data.method = method;
1718 #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
1719 for (tmp = jlist->list; tmp; tmp = tmp->next)
1720 mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr);
1721 #else
1722 // FIXME: This won't work since it ends up calling mono_create_jump_trampoline () which returns a trampoline
1723 // for gshared methods
1724 for (tmp = jlist->list; tmp; tmp = tmp->next) {
1725 ERROR_DECL (error);
1726 mono_arch_patch_code (NULL, NULL, domain, tmp->data, &patch_info, TRUE, error);
1727 mono_error_assert_ok (error);
1729 #endif
1733 void
1734 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1736 MonoGenericInst *inst;
1737 int i;
1739 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1741 if (context && context->class_inst) {
1742 inst = context->class_inst;
1743 for (i = 0; i < inst->type_argc; ++i) {
1744 MonoType *type = inst->type_argv [i];
1746 if (mini_is_gsharedvt_gparam (type))
1747 gsctx->is_gsharedvt = TRUE;
1750 if (context && context->method_inst) {
1751 inst = context->method_inst;
1753 for (i = 0; i < inst->type_argc; ++i) {
1754 MonoType *type = inst->type_argv [i];
1756 if (mini_is_gsharedvt_gparam (type))
1757 gsctx->is_gsharedvt = TRUE;
1763 * LOCKING: Acquires the jit code hash lock.
1765 MonoJitInfo*
1766 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1768 MonoJitInfo *ji;
1769 static gboolean inited = FALSE;
1770 static int lookups = 0;
1771 static int failed_lookups = 0;
1773 mono_domain_jit_code_hash_lock (domain);
1774 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1775 if (!ji && shared) {
1776 /* Try generic sharing */
1777 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1778 if (ji && !ji->has_generic_jit_info)
1779 ji = NULL;
1780 if (!inited) {
1781 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1782 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1783 inited = TRUE;
1786 ++lookups;
1787 if (!ji)
1788 ++failed_lookups;
1790 mono_domain_jit_code_hash_unlock (domain);
1792 return ji;
1795 static MonoJitInfo*
1796 lookup_method (MonoDomain *domain, MonoMethod *method)
1798 ERROR_DECL (error);
1799 MonoJitInfo *ji;
1800 MonoMethod *shared;
1802 ji = mini_lookup_method (domain, method, NULL);
1804 if (!ji) {
1805 if (!mono_method_is_generic_sharable (method, FALSE))
1806 return NULL;
1807 shared = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1808 mono_error_assert_ok (error);
1809 ji = mini_lookup_method (domain, method, shared);
1812 return ji;
1815 MonoClass*
1816 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
1818 ERROR_DECL (error);
1819 MonoClass *klass;
1821 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1822 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1823 if (context) {
1824 klass = mono_class_inflate_generic_class_checked (klass, context, error);
1825 mono_error_cleanup (error); /* FIXME don't swallow the error */
1827 } else {
1828 klass = mono_class_get_and_inflate_typespec_checked (m_class_get_image (method->klass), token, context, error);
1829 mono_error_cleanup (error); /* FIXME don't swallow the error */
1831 if (klass)
1832 mono_class_init (klass);
1833 return klass;
1836 #if ENABLE_JIT_MAP
1837 static FILE* perf_map_file;
1839 void
1840 mono_enable_jit_map (void)
1842 if (!perf_map_file) {
1843 char name [64];
1844 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1845 unlink (name);
1846 perf_map_file = fopen (name, "w");
1850 void
1851 mono_emit_jit_tramp (void *start, int size, const char *desc)
1853 if (perf_map_file)
1854 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1857 void
1858 mono_emit_jit_map (MonoJitInfo *jinfo)
1860 if (perf_map_file) {
1861 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1862 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1863 g_free (name);
1867 gboolean
1868 mono_jit_map_is_enabled (void)
1870 return perf_map_file != NULL;
1873 #endif
1875 static void
1876 no_gsharedvt_in_wrapper (void)
1878 g_assert_not_reached ();
1882 Overall algorithm:
1884 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.
1885 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1886 Dependency management in this case is too complex to justify implementing it.
1888 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1890 TODO:
1891 Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
1892 Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
1893 Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
1894 Maybe pool JitCompilationEntry, specially those with an inited cond var;
1896 typedef struct {
1897 MonoMethod *method;
1898 MonoDomain *domain;
1899 int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
1900 int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
1901 int threads_waiting; /* Number of threads waiting on this job */
1902 gboolean has_cond; /* True if @cond was initialized */
1903 gboolean done; /* True if the method finished JIT'ing */
1904 MonoCoopCond cond; /* Cond sleeping threads wait one */
1905 } JitCompilationEntry;
1907 typedef struct {
1908 GPtrArray *in_flight_methods; //JitCompilationEntry*
1909 MonoCoopMutex lock;
1910 } JitCompilationData;
1913 Timeout, in millisecounds, that we wait other threads to finish JITing.
1914 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.
1916 #define MAX_JIT_TIMEOUT_MS 1000
1919 static JitCompilationData compilation_data;
1920 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts;
1922 static void
1923 mini_jit_init_job_control (void)
1925 mono_coop_mutex_init (&compilation_data.lock);
1926 compilation_data.in_flight_methods = g_ptr_array_new ();
1929 static void
1930 lock_compilation_data (void)
1932 mono_coop_mutex_lock (&compilation_data.lock);
1935 static void
1936 unlock_compilation_data (void)
1938 mono_coop_mutex_unlock (&compilation_data.lock);
1941 static JitCompilationEntry*
1942 find_method (MonoMethod *method, MonoDomain *domain)
1944 int i;
1945 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1946 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1947 if (e->method == method && e->domain == domain)
1948 return e;
1951 return NULL;
1954 static void
1955 add_current_thread (MonoJitTlsData *jit_tls)
1957 ++jit_tls->active_jit_methods;
1960 static void
1961 unref_jit_entry (JitCompilationEntry *entry)
1963 --entry->ref_count;
1964 if (entry->ref_count)
1965 return;
1966 if (entry->has_cond)
1967 mono_coop_cond_destroy (&entry->cond);
1968 g_free (entry);
1972 * Returns true if this method waited successfully for another thread to JIT it
1974 static gboolean
1975 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1977 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1978 JitCompilationEntry *entry;
1980 static gboolean inited;
1981 if (!inited) {
1982 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1983 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1984 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1985 mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts);
1986 inited = TRUE;
1989 lock_compilation_data ();
1991 if (!(entry = find_method (method, domain))) {
1992 entry = g_new0 (JitCompilationEntry, 1);
1993 entry->method = method;
1994 entry->domain = domain;
1995 entry->compilation_count = entry->ref_count = 1;
1996 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1997 g_assert (find_method (method, domain) == entry);
1998 add_current_thread (jit_tls);
2000 unlock_compilation_data ();
2001 return FALSE;
2002 } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) {
2003 //We can't suspend the current thread if it's already JITing a method.
2004 //Dependency management is too compilated and we want to get rid of this anyways.
2006 //We can't suspend the current thread if it's running a protected block (such as a cctor)
2007 //We can't rely only on JIT nesting as cctor's can be run from outside the JIT.
2009 //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling
2010 ++entry->compilation_count;
2011 ++jit_methods_multiple;
2012 ++jit_tls->active_jit_methods;
2014 unlock_compilation_data ();
2015 return FALSE;
2016 } else {
2017 ++jit_methods_waited;
2018 ++entry->ref_count;
2020 if (!entry->has_cond) {
2021 mono_coop_cond_init (&entry->cond);
2022 entry->has_cond = TRUE;
2025 while (TRUE) {
2026 ++entry->threads_waiting;
2028 g_assert (entry->has_cond);
2029 mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS);
2030 --entry->threads_waiting;
2032 if (entry->done) {
2033 unref_jit_entry (entry);
2034 unlock_compilation_data ();
2035 return TRUE;
2036 } else {
2037 //We hit the timeout or a spurious wakeup, fallback to JITing
2038 g_assert (entry->ref_count > 1);
2039 unref_jit_entry (entry);
2040 ++jit_spurious_wakeups_or_timeouts;
2042 ++entry->compilation_count;
2043 ++jit_methods_multiple;
2044 ++jit_tls->active_jit_methods;
2046 unlock_compilation_data ();
2047 return FALSE;
2053 static void
2054 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2056 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2058 lock_compilation_data ();
2060 g_assert (jit_tls->active_jit_methods > 0);
2061 --jit_tls->active_jit_methods;
2063 JitCompilationEntry *entry = find_method (method, target_domain);
2064 g_assert (entry); // It would be weird to fail
2065 entry->done = TRUE;
2067 if (entry->threads_waiting) {
2068 g_assert (entry->has_cond);
2069 mono_coop_cond_broadcast (&entry->cond);
2072 if (--entry->compilation_count == 0) {
2073 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2074 unref_jit_entry (entry);
2077 unlock_compilation_data ();
2080 static MonoJitInfo*
2081 create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
2083 MonoDomain *domain = mono_get_root_domain ();
2084 MonoJitInfo *jinfo;
2085 guint8 *uw_info;
2086 guint32 info_len;
2088 if (info->uw_info) {
2089 uw_info = info->uw_info;
2090 info_len = info->uw_info_len;
2091 } else {
2092 uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
2095 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
2096 jinfo->d.method = wrapper;
2097 jinfo->code_start = info->code;
2098 jinfo->code_size = info->code_size;
2099 jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
2101 if (!info->uw_info)
2102 g_free (uw_info);
2104 return jinfo;
2107 static gpointer
2108 compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error)
2110 MonoJitInfo *jinfo;
2111 gpointer code;
2113 if (mono_llvm_only) {
2114 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2115 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2117 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2119 * These wrappers are only created for signatures which are in the program, but
2120 * sometimes we load methods too eagerly and have to create them even if they
2121 * will never be called.
2123 return no_gsharedvt_in_wrapper;
2128 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2129 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2130 MonoMethod *nm;
2131 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
2133 if (!piinfo->addr) {
2134 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
2135 piinfo->addr = mono_lookup_internal_call (method);
2136 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
2137 #ifdef HOST_WIN32
2138 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);
2139 #else
2140 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);
2141 #endif
2142 else
2143 mono_lookup_pinvoke_call (method, NULL, NULL);
2145 nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
2146 gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error);
2147 return_val_if_nok (error, NULL);
2148 code = mono_get_addr_from_ftnptr (compiled_method);
2149 jinfo = mono_jit_info_table_find (target_domain, code);
2150 if (!jinfo)
2151 jinfo = mono_jit_info_table_find (mono_domain_get (), code);
2152 if (jinfo)
2153 MONO_PROFILER_RAISE (jit_done, (method, jinfo));
2154 return code;
2155 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
2156 const char *name = method->name;
2157 char *full_name;
2158 MonoMethod *nm;
2160 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
2161 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
2162 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
2163 g_assert (mi);
2165 * We need to make sure this wrapper
2166 * is compiled because it might end up
2167 * in an (M)RGCTX if generic sharing
2168 * is enabled, and would be called
2169 * indirectly. If it were a
2170 * trampoline we'd try to patch that
2171 * indirect call, which is not
2172 * possible.
2174 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
2175 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2176 if (mono_llvm_only) {
2177 nm = mono_marshal_get_delegate_invoke (method, NULL);
2178 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2179 return_val_if_nok (error, NULL);
2180 return mono_get_addr_from_ftnptr (compiled_ptr);
2183 /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */
2184 if (mono_use_interpreter)
2185 return NULL;
2187 return mono_create_delegate_trampoline (target_domain, method->klass);
2188 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
2189 nm = mono_marshal_get_delegate_begin_invoke (method);
2190 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2191 return_val_if_nok (error, NULL);
2192 return mono_get_addr_from_ftnptr (compiled_ptr);
2193 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
2194 nm = mono_marshal_get_delegate_end_invoke (method);
2195 gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error);
2196 return_val_if_nok (error, NULL);
2197 return mono_get_addr_from_ftnptr (compiled_ptr);
2201 full_name = mono_method_full_name (method, TRUE);
2202 mono_error_set_invalid_program (error, "Unrecognizable runtime implemented method '%s'", full_name);
2203 g_free (full_name);
2204 return NULL;
2207 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2208 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2210 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
2211 static MonoTrampInfo *in_tinfo, *out_tinfo;
2212 MonoTrampInfo *tinfo;
2213 MonoJitInfo *jinfo;
2214 gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN;
2216 if (is_in && in_tinfo)
2217 return in_tinfo->code;
2218 else if (!is_in && out_tinfo)
2219 return out_tinfo->code;
2222 * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH
2223 * works.
2224 * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms
2226 if (mono_ee_features.use_aot_trampolines)
2227 mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo);
2228 else
2229 mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE);
2230 jinfo = create_jit_info_for_trampoline (method, tinfo);
2231 mono_jit_info_table_add (mono_get_root_domain (), jinfo);
2232 if (is_in)
2233 in_tinfo = tinfo;
2234 else
2235 out_tinfo = tinfo;
2236 return tinfo->code;
2240 return NULL;
2243 static gpointer
2244 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2246 MonoDomain *target_domain, *domain = mono_domain_get ();
2247 MonoJitInfo *info;
2248 gpointer code = NULL, p;
2249 MonoJitInfo *ji;
2250 MonoJitICallInfo *callinfo = NULL;
2251 WrapperInfo *winfo = NULL;
2252 gboolean use_interp = FALSE;
2254 error_init (error);
2256 if (mono_ee_features.force_use_interpreter && !jit_only)
2257 use_interp = TRUE;
2258 if (!use_interp && mono_interp_only_classes) {
2259 for (GSList *l = mono_interp_only_classes; l; l = l->next) {
2260 if (!strcmp (m_class_get_name (method->klass), (char*)l->data))
2261 use_interp = TRUE;
2264 if (use_interp) {
2265 code = mini_get_interp_callbacks ()->create_method_pointer (method, error);
2266 if (code)
2267 return code;
2270 if (mono_llvm_only)
2271 /* Should be handled by the caller */
2272 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2275 * ICALL wrappers are handled specially, since there is only one copy of them
2276 * shared by all appdomains.
2278 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2279 winfo = mono_marshal_get_wrapper_info (method);
2280 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2281 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2282 g_assert (callinfo);
2284 /* Must be domain neutral since there is only one copy */
2285 opt |= MONO_OPT_SHARED;
2286 } else {
2287 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2288 opt &= ~MONO_OPT_SHARED;
2291 if (opt & MONO_OPT_SHARED)
2292 target_domain = mono_get_root_domain ();
2293 else
2294 target_domain = domain;
2296 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2297 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2299 g_assert (info);
2300 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2301 MonoGenericContext *ctx = NULL;
2302 if (method->is_inflated)
2303 ctx = mono_method_get_context (method);
2304 method = info->d.synchronized_inner.method;
2305 if (ctx) {
2306 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2307 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2312 lookup_start:
2313 info = lookup_method (target_domain, method);
2314 if (info) {
2315 /* We can't use a domain specific method in another domain */
2316 if (! ((domain != target_domain) && !info->domain_neutral)) {
2317 MonoVTable *vtable;
2319 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2320 vtable = mono_class_vtable_checked (domain, method->klass, error);
2321 if (!is_ok (error))
2322 return NULL;
2323 g_assert (vtable);
2324 if (!mono_runtime_class_init_full (vtable, error))
2325 return NULL;
2326 return mono_create_ftnptr (target_domain, info->code_start);
2330 #ifdef MONO_USE_AOT_COMPILER
2331 if (opt & MONO_OPT_AOT) {
2332 MonoDomain *domain = NULL;
2334 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2335 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2336 g_assert (info);
2337 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN || info->subtype == WRAPPER_SUBTYPE_INTERP_LMF)
2338 /* AOT'd wrappers for interp must be owned by root domain */
2339 domain = mono_get_root_domain ();
2342 if (!domain)
2343 domain = mono_domain_get ();
2345 mono_class_init (method->klass);
2347 if ((code = mono_aot_get_method (domain, method, error))) {
2348 MonoVTable *vtable;
2350 if (mono_gc_is_critical_method (method)) {
2352 * The suspend code needs to be able to lookup these methods by ip in async context,
2353 * so preload their jit info.
2355 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2356 g_assert (ji);
2360 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2361 * This is not a problem, since it will be initialized when the method is first
2362 * called by init_method ().
2364 if (!mono_llvm_only && !mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2365 vtable = mono_class_vtable_checked (domain, method->klass, error);
2366 mono_error_assert_ok (error);
2367 if (!mono_runtime_class_init_full (vtable, error))
2368 return NULL;
2371 if (!is_ok (error))
2372 return NULL;
2374 #endif
2376 if (!code)
2377 code = compile_special (method, target_domain, error);
2379 if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_UNKNOWN)
2380 code = mini_get_interp_callbacks ()->create_method_pointer (method, error);
2382 if (!code) {
2383 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
2384 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type is not fully instantiated.");
2385 return NULL;
2388 if (mono_aot_only) {
2389 char *fullname = mono_method_full_name (method, TRUE);
2390 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);
2391 g_free (fullname);
2393 return NULL;
2396 if (wait_or_register_method_to_compile (method, target_domain))
2397 goto lookup_start;
2398 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2399 unregister_method_for_compile (method, target_domain);
2401 if (!mono_error_ok (error))
2402 return NULL;
2404 if (!code && mono_llvm_only) {
2405 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2406 g_assert_not_reached ();
2409 if (!code)
2410 return NULL;
2412 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2413 MonoDomain *d;
2416 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2418 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2419 g_assert (ji);
2422 p = mono_create_ftnptr (target_domain, code);
2424 if (callinfo) {
2425 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2426 mono_loader_lock ();
2427 mono_jit_lock ();
2428 if (!callinfo->wrapper) {
2429 callinfo->wrapper = p;
2430 mono_register_jit_icall_wrapper (callinfo, p);
2432 mono_jit_unlock ();
2433 mono_loader_unlock ();
2436 return p;
2439 gpointer
2440 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2442 gpointer code;
2444 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2445 return code;
2449 * mono_jit_compile_method_jit_only:
2451 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2453 gpointer
2454 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2456 gpointer code;
2458 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2459 return code;
2462 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2463 static void
2464 invalidated_delegate_trampoline (char *desc)
2466 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2467 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2468 desc);
2470 #endif
2473 * mono_jit_free_method:
2475 * Free all memory allocated by the JIT for METHOD.
2477 static void
2478 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2480 MonoJitDynamicMethodInfo *ji;
2481 gboolean destroy = TRUE;
2482 GHashTableIter iter;
2483 MonoJumpList *jlist;
2484 MonoJitDomainInfo *info = domain_jit_info (domain);
2486 g_assert (method->dynamic);
2488 if (mono_use_interpreter) {
2489 mono_domain_jit_code_hash_lock (domain);
2490 /* InterpMethod is allocated in the domain mempool */
2491 if (mono_internal_hash_table_lookup (&info->interp_code_hash, method))
2492 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2493 mono_domain_jit_code_hash_unlock (domain);
2496 mono_domain_lock (domain);
2497 ji = mono_dynamic_code_hash_lookup (domain, method);
2498 mono_domain_unlock (domain);
2500 if (!ji)
2501 return;
2503 mono_debug_remove_method (method, domain);
2504 mono_lldb_remove_method (domain, method, ji);
2506 mono_domain_lock (domain);
2507 g_hash_table_remove (info->dynamic_code_hash, method);
2508 mono_domain_jit_code_hash_lock (domain);
2509 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2510 mono_domain_jit_code_hash_unlock (domain);
2511 g_hash_table_remove (info->jump_trampoline_hash, method);
2512 g_hash_table_remove (info->seq_points, method);
2514 /* requires the domain lock - took above */
2515 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2517 /* Remove jump targets in this method */
2518 g_hash_table_iter_init (&iter, info->jump_target_hash);
2519 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2520 GSList *tmp, *remove;
2522 remove = NULL;
2523 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2524 guint8 *ip = (guint8 *)tmp->data;
2526 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2527 remove = g_slist_prepend (remove, tmp);
2529 for (tmp = remove; tmp; tmp = tmp->next) {
2530 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2532 g_slist_free (remove);
2534 mono_domain_unlock (domain);
2536 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2537 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2539 * Instead of freeing the code, change it to call an error routine
2540 * so people can fix their code.
2542 char *type = mono_type_full_name (m_class_get_byval_arg (method->klass));
2543 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2545 g_free (type);
2546 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2547 destroy = FALSE;
2549 #endif
2552 * This needs to be done before freeing code_mp, since the code address is the
2553 * key in the table, so if we free the code_mp first, another thread can grab the
2554 * same code address and replace our entry in the table.
2556 mono_jit_info_table_remove (domain, ji->ji);
2558 if (destroy)
2559 mono_code_manager_destroy (ji->code_mp);
2560 g_free (ji);
2563 gpointer
2564 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2566 MonoDomain *target_domain;
2567 MonoJitInfo *info;
2569 if (default_opt & MONO_OPT_SHARED)
2570 target_domain = mono_get_root_domain ();
2571 else
2572 target_domain = domain;
2574 info = lookup_method (target_domain, method);
2575 if (info) {
2576 /* We can't use a domain specific method in another domain */
2577 if (! ((domain != target_domain) && !info->domain_neutral)) {
2578 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2579 if (ji)
2580 *ji = info;
2581 return info->code_start;
2585 if (ji)
2586 *ji = NULL;
2587 return NULL;
2590 static guint32 bisect_opt = 0;
2591 static GHashTable *bisect_methods_hash = NULL;
2593 void
2594 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2596 FILE *file;
2597 char method_name [2048];
2599 bisect_opt = opt;
2600 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2601 g_assert (bisect_methods_hash);
2603 file = fopen (method_list_filename, "r");
2604 g_assert (file);
2606 while (fgets (method_name, sizeof (method_name), file)) {
2607 size_t len = strlen (method_name);
2608 g_assert (len > 0);
2609 g_assert (method_name [len - 1] == '\n');
2610 method_name [len - 1] = 0;
2611 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2613 g_assert (feof (file));
2616 gboolean mono_do_single_method_regression = FALSE;
2617 guint32 mono_single_method_regression_opt = 0;
2618 MonoMethod *mono_current_single_method;
2619 GSList *mono_single_method_list;
2620 GHashTable *mono_single_method_hash;
2622 guint32
2623 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2625 g_assert (method);
2627 if (bisect_methods_hash) {
2628 char *name = mono_method_full_name (method, TRUE);
2629 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2630 g_free (name);
2631 if (res)
2632 return default_opt | bisect_opt;
2634 if (!mono_do_single_method_regression)
2635 return default_opt;
2636 if (!mono_current_single_method) {
2637 if (!mono_single_method_hash)
2638 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2639 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2640 g_hash_table_insert (mono_single_method_hash, method, method);
2641 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2643 return default_opt;
2645 if (method == mono_current_single_method)
2646 return mono_single_method_regression_opt;
2647 return default_opt;
2650 gpointer
2651 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2653 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2656 typedef struct {
2657 MonoMethod *method;
2658 gpointer compiled_method;
2659 gpointer runtime_invoke;
2660 MonoVTable *vtable;
2661 MonoDynCallInfo *dyn_call_info;
2662 MonoClass *ret_box_class;
2663 MonoMethodSignature *sig;
2664 gboolean gsharedvt_invoke;
2665 gboolean use_interp;
2666 gpointer *wrapper_arg;
2667 } RuntimeInvokeInfo;
2669 static RuntimeInvokeInfo*
2670 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error)
2672 MonoMethod *invoke;
2673 RuntimeInvokeInfo *info;
2675 info = g_new0 (RuntimeInvokeInfo, 1);
2676 info->compiled_method = compiled_method;
2677 info->use_interp = use_interp;
2678 if (mono_llvm_only && method->string_ctor)
2679 info->sig = mono_marshal_get_string_ctor_signature (method);
2680 else
2681 info->sig = mono_method_signature (method);
2683 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2684 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2685 if (!mono_error_ok (error))
2686 return NULL;
2687 g_assert (info->vtable);
2689 MonoMethodSignature *sig = info->sig;
2690 MonoType *ret_type;
2693 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2694 * in full-aot mode, so we use a slower, but more generic wrapper if
2695 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2697 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2698 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2699 gboolean supported = TRUE;
2700 int i;
2702 if (method->string_ctor)
2703 sig = mono_marshal_get_string_ctor_signature (method);
2705 for (i = 0; i < sig->param_count; ++i) {
2706 MonoType *t = sig->params [i];
2708 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2709 supported = FALSE;
2712 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2713 supported = FALSE;
2715 if (supported) {
2716 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2717 if (mini_debug_options.dyn_runtime_invoke)
2718 g_assert (info->dyn_call_info);
2721 #endif
2723 ret_type = sig->ret;
2724 switch (ret_type->type) {
2725 case MONO_TYPE_VOID:
2726 break;
2727 case MONO_TYPE_I1:
2728 case MONO_TYPE_U1:
2729 case MONO_TYPE_I2:
2730 case MONO_TYPE_U2:
2731 case MONO_TYPE_I4:
2732 case MONO_TYPE_U4:
2733 case MONO_TYPE_I:
2734 case MONO_TYPE_U:
2735 case MONO_TYPE_I8:
2736 case MONO_TYPE_U8:
2737 case MONO_TYPE_BOOLEAN:
2738 case MONO_TYPE_CHAR:
2739 case MONO_TYPE_R4:
2740 case MONO_TYPE_R8:
2741 info->ret_box_class = mono_class_from_mono_type (ret_type);
2742 break;
2743 case MONO_TYPE_PTR:
2744 info->ret_box_class = mono_defaults.int_class;
2745 break;
2746 case MONO_TYPE_STRING:
2747 case MONO_TYPE_CLASS:
2748 case MONO_TYPE_ARRAY:
2749 case MONO_TYPE_SZARRAY:
2750 case MONO_TYPE_OBJECT:
2751 break;
2752 case MONO_TYPE_GENERICINST:
2753 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2754 info->ret_box_class = mono_class_from_mono_type (ret_type);
2755 break;
2756 case MONO_TYPE_VALUETYPE:
2757 info->ret_box_class = mono_class_from_mono_type (ret_type);
2758 break;
2759 default:
2760 g_assert_not_reached ();
2761 break;
2764 if (info->use_interp)
2765 return info;
2767 if (!info->dyn_call_info) {
2768 if (mono_llvm_only) {
2769 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2770 g_assert_not_reached ();
2771 #endif
2772 info->gsharedvt_invoke = TRUE;
2773 if (!callee_gsharedvt) {
2774 /* Invoke a gsharedvt out wrapper instead */
2775 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2776 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2778 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2779 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2781 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2782 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2783 g_free (wrapper_sig);
2785 info->compiled_method = mono_jit_compile_method (wrapper, error);
2786 if (!mono_error_ok (error)) {
2787 g_free (info);
2788 return NULL;
2790 } else {
2791 /* Gsharedvt methods can be invoked the same way */
2792 /* The out wrapper has the same signature as the compiled gsharedvt method */
2793 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2795 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2797 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2798 g_free (wrapper_sig);
2801 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2802 if (!mono_error_ok (error)) {
2803 g_free (info);
2804 return NULL;
2808 return info;
2811 static MonoObject*
2812 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2814 MonoMethodSignature *sig = info->sig;
2815 MonoDomain *domain = mono_domain_get ();
2816 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2817 gpointer *args;
2818 gpointer retval_ptr;
2819 guint8 retval [256];
2820 gpointer *param_refs;
2821 int i, pindex;
2823 error_init (error);
2825 g_assert (info->gsharedvt_invoke);
2828 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2829 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2830 * signatures, so we only have to generate runtime invoke wrappers for these
2831 * signatures.
2832 * This code also handles invocation of gsharedvt methods directly, no
2833 * out wrappers are used in that case.
2835 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2836 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2837 pindex = 0;
2839 * The runtime invoke wrappers expects pointers to primitive types, so have to
2840 * use indirections.
2842 if (sig->hasthis)
2843 args [pindex ++] = &obj;
2844 if (sig->ret->type != MONO_TYPE_VOID) {
2845 retval_ptr = (gpointer)&retval;
2846 args [pindex ++] = &retval_ptr;
2848 for (i = 0; i < sig->param_count; ++i) {
2849 MonoType *t = sig->params [i];
2851 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2852 MonoClass *klass = mono_class_from_mono_type (t);
2853 guint8 *nullable_buf;
2854 int size;
2856 size = mono_class_value_size (klass, NULL);
2857 nullable_buf = g_alloca (size);
2858 g_assert (nullable_buf);
2860 /* The argument pointed to by params [i] is either a boxed vtype or null */
2861 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2862 params [i] = nullable_buf;
2865 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2866 param_refs [i] = params [i];
2867 params [i] = &(param_refs [i]);
2869 args [pindex ++] = &params [i];
2871 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2872 args [pindex ++] = &info->wrapper_arg;
2874 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2876 runtime_invoke (NULL, args, exc, info->compiled_method);
2877 if (exc && *exc)
2878 return NULL;
2880 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2881 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2882 else
2883 return *(MonoObject**)retval;
2887 * mono_jit_runtime_invoke:
2888 * \param method: the method to invoke
2889 * \param obj: this pointer
2890 * \param params: array of parameter values.
2891 * \param exc: Set to the exception raised in the managed method.
2892 * \param error: error or caught exception object
2893 * If \p exc is NULL, \p error is thrown instead.
2894 * If coop is enabled, \p exc argument is ignored -
2895 * all exceptions are caught and propagated through \p error
2897 static MonoObject*
2898 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2900 MonoMethod *invoke, *callee;
2901 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2902 MonoDomain *domain = mono_domain_get ();
2903 MonoJitDomainInfo *domain_info;
2904 RuntimeInvokeInfo *info, *info2;
2905 MonoJitInfo *ji = NULL;
2906 gboolean callee_gsharedvt = FALSE;
2908 if (mono_ee_features.force_use_interpreter)
2909 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
2911 error_init (error);
2912 if (exc)
2913 *exc = NULL;
2915 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2916 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2917 return NULL;
2920 domain_info = domain_jit_info (domain);
2922 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2924 if (!info) {
2925 if (mono_security_core_clr_enabled ()) {
2927 * This might be redundant since mono_class_vtable () already does this,
2928 * but keep it just in case for moonlight.
2930 mono_class_setup_vtable (method->klass);
2931 if (mono_class_has_failure (method->klass)) {
2932 mono_error_set_for_class_failure (error, method->klass);
2933 if (exc)
2934 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2935 return NULL;
2939 gpointer compiled_method;
2941 callee = method;
2942 if (m_class_get_rank (method->klass) && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2943 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2945 * Array Get/Set/Address methods. The JIT implements them using inline code
2946 * inside the runtime invoke wrappers, so no need to compile them.
2948 if (mono_aot_only) {
2950 * Call a wrapper, since the runtime invoke wrapper was not generated.
2952 MonoMethod *wrapper;
2954 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2955 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2956 callee = wrapper;
2957 } else {
2958 callee = NULL;
2962 gboolean use_interp = FALSE;
2964 if (callee) {
2965 compiled_method = mono_jit_compile_method_jit_only (callee, error);
2966 if (!compiled_method) {
2967 g_assert (!mono_error_ok (error));
2969 if (mono_use_interpreter)
2970 use_interp = TRUE;
2971 else
2972 return NULL;
2973 } else {
2974 if (mono_llvm_only) {
2975 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2976 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2977 if (callee_gsharedvt)
2978 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2981 if (!callee_gsharedvt)
2982 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2984 } else {
2985 compiled_method = NULL;
2988 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error);
2989 if (!mono_error_ok (error))
2990 return NULL;
2992 mono_domain_lock (domain);
2993 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2994 mono_domain_unlock (domain);
2995 if (info2) {
2996 g_free (info);
2997 info = info2;
3002 * We need this here because mono_marshal_get_runtime_invoke can place
3003 * the helper method in System.Object and not the target class.
3005 if (!mono_runtime_class_init_full (info->vtable, error)) {
3006 if (exc)
3007 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3008 return NULL;
3011 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
3012 we always catch the exception and propagate it through the MonoError */
3013 gboolean catchExcInMonoError =
3014 (exc == NULL) && mono_threads_are_safepoints_enabled ();
3015 MonoObject *invoke_exc = NULL;
3016 if (catchExcInMonoError)
3017 exc = &invoke_exc;
3019 /* The wrappers expect this to be initialized to NULL */
3020 if (exc)
3021 *exc = NULL;
3023 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3024 static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
3025 if (info->dyn_call_info) {
3026 if (!dyn_runtime_invoke) {
3027 mono_domain_lock (domain);
3029 invoke = mono_marshal_get_runtime_invoke_dynamic ();
3030 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
3031 if (!dyn_runtime_invoke && mono_use_interpreter) {
3032 info->use_interp = TRUE;
3033 info->dyn_call_info = NULL;
3034 } else if (!mono_error_ok (error)) {
3035 mono_domain_unlock (domain);
3036 return NULL;
3038 mono_domain_unlock (domain);
3041 if (info->dyn_call_info) {
3042 MonoMethodSignature *sig = mono_method_signature (method);
3043 gpointer *args;
3044 int i, pindex, buf_size;
3045 guint8 *buf;
3046 guint8 retval [256];
3048 /* Convert the arguments to the format expected by start_dyn_call () */
3049 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
3050 pindex = 0;
3051 if (sig->hasthis)
3052 args [pindex ++] = &obj;
3053 for (i = 0; i < sig->param_count; ++i) {
3054 MonoType *t = sig->params [i];
3056 if (t->byref) {
3057 args [pindex ++] = &params [i];
3058 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
3059 args [pindex ++] = &params [i];
3060 } else {
3061 args [pindex ++] = params [i];
3065 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
3067 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
3068 buf = g_alloca (buf_size);
3069 g_assert (buf);
3071 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
3073 dyn_runtime_invoke (buf, exc, info->compiled_method);
3074 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
3076 if (catchExcInMonoError && *exc != NULL) {
3077 mono_error_set_exception_instance (error, (MonoException*) *exc);
3078 return NULL;
3081 if (info->ret_box_class)
3082 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
3083 else
3084 return *(MonoObject**)retval;
3086 #endif
3088 if (info->use_interp) {
3089 error_init (error);
3090 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
3093 MonoObject *result;
3095 if (mono_llvm_only) {
3096 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
3097 if (!is_ok (error))
3098 return NULL;
3099 } else {
3100 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
3102 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
3104 if (catchExcInMonoError && *exc != NULL)
3105 mono_error_set_exception_instance (error, (MonoException*) *exc);
3106 return result;
3109 typedef struct {
3110 MonoVTable *vtable;
3111 int slot;
3112 } IMTTrampInfo;
3114 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
3117 * mini_llvmonly_initial_imt_tramp:
3119 * This function is called the first time a call is made through an IMT trampoline.
3120 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
3122 static gpointer
3123 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3125 IMTTrampInfo *info = (IMTTrampInfo*)arg;
3126 gpointer *imt;
3127 gpointer *ftndesc;
3128 IMTTrampFunc func;
3130 mono_vtable_build_imt_slot (info->vtable, info->slot);
3132 imt = (gpointer*)info->vtable;
3133 imt -= MONO_IMT_SIZE;
3135 /* Return what the real IMT trampoline returns */
3136 ftndesc = imt [info->slot];
3137 func = ftndesc [0];
3139 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
3140 /* Happens when the imt slot contains only a generic virtual method */
3141 return NULL;
3142 return func ((gpointer *)ftndesc [1], imt_method);
3145 /* This is called indirectly through an imt slot. */
3146 static gpointer
3147 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3149 int i = 0;
3151 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
3152 while (arg [i] && arg [i] != imt_method)
3153 i += 2;
3154 g_assert (arg [i]);
3156 return arg [i + 1];
3159 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
3160 static gpointer
3161 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
3163 //g_assert (arg [0] == imt_method);
3164 return arg [1];
3167 static gpointer
3168 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
3170 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
3171 if (arg [0] == imt_method)
3172 return arg [1];
3173 else
3174 return arg [3];
3177 static gpointer
3178 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
3180 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
3181 if (arg [0] == imt_method)
3182 return arg [1];
3183 else if (arg [2] == imt_method)
3184 return arg [3];
3185 else
3186 return arg [5];
3190 * A version of the imt trampoline used for generic virtual/variant iface methods.
3191 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
3192 * in the search table. The original JIT code had a 'fallback' trampoline it could
3193 * call, but we can't do that, so we just return NULL, and the compiled code
3194 * will handle it.
3196 static gpointer
3197 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
3199 int i = 0;
3201 while (arg [i] && arg [i] != imt_method)
3202 i += 2;
3203 if (!arg [i])
3204 return NULL;
3206 return arg [i + 1];
3209 static gpointer
3210 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
3212 gpointer *buf;
3213 gpointer *res;
3214 int i, index, real_count;
3215 gboolean virtual_generic = FALSE;
3218 * Create an array which is passed to the imt trampoline functions.
3219 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
3222 real_count = 0;
3223 for (i = 0; i < count; ++i) {
3224 MonoIMTCheckItem *item = imt_entries [i];
3226 if (item->is_equals)
3227 real_count ++;
3228 if (item->has_target_code)
3229 virtual_generic = TRUE;
3233 * Initialize all vtable entries reachable from this imt slot, so the compiled
3234 * code doesn't have to check it.
3236 for (i = 0; i < count; ++i) {
3237 MonoIMTCheckItem *item = imt_entries [i];
3238 int vt_slot;
3240 if (!item->is_equals || item->has_target_code)
3241 continue;
3242 vt_slot = item->value.vtable_slot;
3243 mono_init_vtable_slot (vtable, vt_slot);
3246 /* Save the entries into an array */
3247 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
3248 index = 0;
3249 for (i = 0; i < count; ++i) {
3250 MonoIMTCheckItem *item = imt_entries [i];
3252 if (!item->is_equals)
3253 continue;
3255 g_assert (item->key);
3256 buf [(index * 2)] = item->key;
3257 if (item->has_target_code)
3258 buf [(index * 2) + 1] = item->value.target_code;
3259 else
3260 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
3261 index ++;
3263 buf [(index * 2)] = NULL;
3264 buf [(index * 2) + 1] = fail_tramp;
3267 * Return a function descriptor for a C function with 'buf' as its argument.
3268 * It will by called by JITted code.
3270 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
3271 switch (real_count) {
3272 case 1:
3273 res [0] = mono_llvmonly_imt_tramp_1;
3274 break;
3275 case 2:
3276 res [0] = mono_llvmonly_imt_tramp_2;
3277 break;
3278 case 3:
3279 res [0] = mono_llvmonly_imt_tramp_3;
3280 break;
3281 default:
3282 res [0] = mono_llvmonly_imt_tramp;
3283 break;
3285 if (virtual_generic || fail_tramp)
3286 res [0] = mono_llvmonly_fallback_imt_tramp;
3287 res [1] = buf;
3289 return res;
3292 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3294 MonoException *exc = NULL;
3295 MonoJitInfo *ji;
3296 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3297 MONO_SIG_HANDLER_GET_CONTEXT;
3299 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3301 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3303 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3304 if (mono_arch_is_int_overflow (ctx, info))
3306 * The spec says this throws ArithmeticException, but MS throws the derived
3307 * OverflowException.
3309 exc = mono_get_exception_overflow ();
3310 else
3311 exc = mono_get_exception_divide_by_zero ();
3312 #else
3313 exc = mono_get_exception_divide_by_zero ();
3314 #endif
3316 if (!ji) {
3317 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3318 goto exit;
3320 mono_handle_native_crash ("SIGFPE", ctx, info);
3321 if (mono_do_crash_chaining) {
3322 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3323 goto exit;
3327 mono_arch_handle_exception (ctx, exc);
3329 exit:
3330 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3333 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3335 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3336 MONO_SIG_HANDLER_GET_CONTEXT;
3338 if (mono_runtime_get_no_exec ())
3339 exit (1);
3342 mono_handle_native_crash ("SIGILL", ctx, info);
3343 if (mono_do_crash_chaining) {
3344 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3345 return;
3348 g_assert_not_reached ();
3351 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3352 #define HAVE_SIG_INFO
3353 #endif
3355 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3357 MonoJitInfo *ji;
3358 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3359 gpointer fault_addr = NULL;
3360 #ifdef HAVE_SIG_INFO
3361 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3362 #else
3363 void *info = NULL;
3364 #endif
3365 MONO_SIG_HANDLER_GET_CONTEXT;
3367 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3368 if (mono_arch_is_single_step_event (info, ctx)) {
3369 mini_get_dbg_callbacks ()->single_step_event (ctx);
3370 return;
3371 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3372 mini_get_dbg_callbacks ()->breakpoint_hit (ctx);
3373 return;
3375 #endif
3377 #if defined(HAVE_SIG_INFO)
3378 #if !defined(HOST_WIN32)
3379 fault_addr = info->si_addr;
3380 if (mono_aot_is_pagefault (info->si_addr)) {
3381 mono_aot_handle_pagefault (info->si_addr);
3382 return;
3384 #endif
3386 /* The thread might no be registered with the runtime */
3387 if (!mono_domain_get () || !jit_tls) {
3388 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3389 return;
3390 mono_handle_native_crash ("SIGSEGV", ctx, info);
3391 if (mono_do_crash_chaining) {
3392 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3393 return;
3396 #endif
3398 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3400 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3401 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3402 return;
3404 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3405 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3406 fault_addr = info->si_addr;
3407 if (fault_addr == NULL) {
3408 MonoContext mctx;
3410 mono_sigctx_to_monoctx (ctx, &mctx);
3412 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3414 #endif
3416 if (jit_tls->stack_size &&
3417 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3419 * The hard-guard page has been hit: there is not much we can do anymore
3420 * Print a hopefully clear message and abort.
3422 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3423 g_assert_not_reached ();
3424 } else {
3425 /* The original handler might not like that it is executed on an altstack... */
3426 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3427 return;
3429 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3431 #else
3433 if (!ji) {
3434 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3435 return;
3437 mono_handle_native_crash ("SIGSEGV", ctx, info);
3439 if (mono_do_crash_chaining) {
3440 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3441 return;
3445 mono_arch_handle_exception (ctx, NULL);
3446 #endif
3449 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3451 MonoException *exc;
3452 MONO_SIG_HANDLER_GET_CONTEXT;
3454 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3456 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3458 mono_arch_handle_exception (ctx, exc);
3460 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3463 #ifndef DISABLE_REMOTING
3464 /* mono_jit_create_remoting_trampoline:
3465 * @method: pointer to the method info
3467 * Creates a trampoline which calls the remoting functions. This
3468 * is used in the vtable of transparent proxies.
3470 * Returns: a pointer to the newly created code
3472 static gpointer
3473 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3475 MonoMethod *nm;
3476 guint8 *addr = NULL;
3478 error_init (error);
3480 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3481 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3482 domain, NULL);
3485 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3486 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3487 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3488 else
3489 nm = method;
3490 return_val_if_nok (error, NULL);
3491 addr = (guint8 *)mono_compile_method_checked (nm, error);
3492 return_val_if_nok (error, NULL);
3493 return mono_get_addr_from_ftnptr (addr);
3495 #endif
3497 static G_GNUC_UNUSED void
3498 no_imt_trampoline (void)
3500 g_assert_not_reached ();
3503 static G_GNUC_UNUSED void
3504 no_vcall_trampoline (void)
3506 g_assert_not_reached ();
3509 static gpointer *vtable_trampolines;
3510 static int vtable_trampolines_size;
3512 gpointer
3513 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3515 int index = slot_index + MONO_IMT_SIZE;
3517 if (mono_llvm_only) {
3518 if (slot_index < 0) {
3519 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3520 // FIXME: Memory management
3521 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3522 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3523 info->vtable = vt;
3524 info->slot = index;
3525 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3526 ftndesc [1] = info;
3527 mono_memory_barrier ();
3528 return ftndesc;
3529 } else {
3530 return NULL;
3534 g_assert (slot_index >= - MONO_IMT_SIZE);
3535 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3536 mono_jit_lock ();
3537 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3538 int new_size;
3539 gpointer new_table;
3541 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3542 while (new_size <= index)
3543 new_size *= 2;
3544 new_table = g_new0 (gpointer, new_size);
3546 if (vtable_trampolines)
3547 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3548 g_free (vtable_trampolines);
3549 mono_memory_barrier ();
3550 vtable_trampolines = (void **)new_table;
3551 vtable_trampolines_size = new_size;
3553 mono_jit_unlock ();
3556 if (!vtable_trampolines [index])
3557 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3558 return vtable_trampolines [index];
3561 static gpointer
3562 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3564 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3567 static gboolean
3568 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3570 if (mono_llvm_only)
3571 return FALSE;
3573 gpointer *imt = (gpointer*)vt;
3574 imt -= MONO_IMT_SIZE;
3576 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3579 static gboolean
3580 is_callee_gsharedvt_variable (gpointer addr)
3582 MonoJitInfo *ji;
3583 gboolean callee_gsharedvt;
3585 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3586 g_assert (ji);
3587 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3588 if (callee_gsharedvt)
3589 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3590 return callee_gsharedvt;
3593 gpointer
3594 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3596 gpointer arg = NULL;
3598 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3599 arg = mini_method_get_rgctx (method);
3602 * Avoid adding gsharedvt in wrappers since they might not exist if
3603 * this delegate is called through a gsharedvt delegate invoke wrapper.
3604 * Instead, encode that the method is gsharedvt in del->extra_arg,
3605 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3607 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3608 g_assert ((((mgreg_t)arg) & 1) == 0);
3609 arg = (gpointer)(((mgreg_t)arg) | 1);
3611 return arg;
3614 void
3615 mini_init_delegate (MonoDelegate *del)
3617 if (mono_use_interpreter)
3618 mini_get_interp_callbacks ()->init_delegate (del);
3619 else if (mono_llvm_only)
3620 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3623 char*
3624 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3626 int abs_offset;
3628 abs_offset = offset;
3629 if (abs_offset < 0)
3630 abs_offset = - abs_offset;
3631 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3634 gpointer
3635 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3637 gboolean is_virtual_generic, is_interface, load_imt_reg;
3638 int offset, idx;
3640 static guint8 **cache = NULL;
3641 static int cache_size = 0;
3643 if (!method)
3644 return NULL;
3646 if (MONO_TYPE_ISSTRUCT (sig->ret))
3647 return NULL;
3649 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3650 is_interface = mono_class_is_interface (method->klass);
3651 load_imt_reg = is_virtual_generic || is_interface;
3653 if (is_interface)
3654 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3655 else
3656 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3658 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3659 g_assert (idx >= 0);
3661 /* Resize the cache to idx + 1 */
3662 if (cache_size < idx + 1) {
3663 mono_jit_lock ();
3664 if (cache_size < idx + 1) {
3665 guint8 **new_cache;
3666 int new_cache_size = idx + 1;
3668 new_cache = g_new0 (guint8*, new_cache_size);
3669 if (cache)
3670 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3671 g_free (cache);
3673 mono_memory_barrier ();
3674 cache = new_cache;
3675 cache_size = new_cache_size;
3677 mono_jit_unlock ();
3680 if (cache [idx])
3681 return cache [idx];
3683 /* FIXME Support more cases */
3684 if (mono_ee_features.use_aot_trampolines) {
3685 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3686 g_assert (cache [idx]);
3687 } else {
3688 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3690 return cache [idx];
3694 * mini_parse_debug_option:
3695 * @option: The option to parse.
3697 * Parses debug options for the mono runtime. The options are the same as for
3698 * the MONO_DEBUG environment variable.
3701 gboolean
3702 mini_parse_debug_option (const char *option)
3704 // Empty string is ok as consequence of appending ",foo"
3705 // without first checking for empty.
3706 if (*option == 0)
3707 return TRUE;
3709 if (!strcmp (option, "handle-sigint"))
3710 mini_debug_options.handle_sigint = TRUE;
3711 else if (!strcmp (option, "keep-delegates"))
3712 mini_debug_options.keep_delegates = TRUE;
3713 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3714 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3715 else if (!strcmp (option, "collect-pagefault-stats"))
3716 mini_debug_options.collect_pagefault_stats = TRUE;
3717 else if (!strcmp (option, "break-on-unverified"))
3718 mini_debug_options.break_on_unverified = TRUE;
3719 else if (!strcmp (option, "no-gdb-backtrace"))
3720 mini_debug_options.no_gdb_backtrace = TRUE;
3721 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3722 mini_debug_options.suspend_on_native_crash = TRUE;
3723 else if (!strcmp (option, "suspend-on-exception"))
3724 mini_debug_options.suspend_on_exception = TRUE;
3725 else if (!strcmp (option, "suspend-on-unhandled"))
3726 mini_debug_options.suspend_on_unhandled = TRUE;
3727 else if (!strcmp (option, "dont-free-domains"))
3728 mono_dont_free_domains = TRUE;
3729 else if (!strcmp (option, "dyn-runtime-invoke"))
3730 mini_debug_options.dyn_runtime_invoke = TRUE;
3731 else if (!strcmp (option, "gdb"))
3732 mini_debug_options.gdb = TRUE;
3733 else if (!strcmp (option, "lldb"))
3734 mini_debug_options.lldb = TRUE;
3735 else if (!strcmp (option, "explicit-null-checks"))
3736 mini_debug_options.explicit_null_checks = TRUE;
3737 else if (!strcmp (option, "gen-seq-points"))
3738 mini_debug_options.gen_sdb_seq_points = TRUE;
3739 else if (!strcmp (option, "gen-compact-seq-points"))
3740 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3741 else if (!strcmp (option, "no-compact-seq-points"))
3742 mini_debug_options.no_seq_points_compact_data = TRUE;
3743 else if (!strcmp (option, "single-imm-size"))
3744 mini_debug_options.single_imm_size = TRUE;
3745 else if (!strcmp (option, "init-stacks"))
3746 mini_debug_options.init_stacks = TRUE;
3747 else if (!strcmp (option, "casts"))
3748 mini_debug_options.better_cast_details = TRUE;
3749 else if (!strcmp (option, "soft-breakpoints"))
3750 mini_debug_options.soft_breakpoints = TRUE;
3751 else if (!strcmp (option, "check-pinvoke-callconv"))
3752 mini_debug_options.check_pinvoke_callconv = TRUE;
3753 else if (!strcmp (option, "use-fallback-tls"))
3754 mini_debug_options.use_fallback_tls = TRUE;
3755 else if (!strcmp (option, "debug-domain-unload"))
3756 mono_enable_debug_domain_unload (TRUE);
3757 else if (!strcmp (option, "partial-sharing"))
3758 mono_set_partial_sharing_supported (TRUE);
3759 else if (!strcmp (option, "align-small-structs"))
3760 mono_align_small_structs = TRUE;
3761 else if (!strcmp (option, "native-debugger-break"))
3762 mini_debug_options.native_debugger_break = TRUE;
3763 else if (!strcmp (option, "disable_omit_fp"))
3764 mini_debug_options.disable_omit_fp = TRUE;
3765 // This is an internal testing feature.
3766 // Every tail. encountered is required to be optimized.
3767 // It is asserted.
3768 else if (!strcmp (option, "test-tailcall-require"))
3769 mini_debug_options.test_tailcall_require = TRUE;
3770 else if (!strcmp (option, "verbose-gdb"))
3771 mini_debug_options.verbose_gdb = TRUE;
3772 else if (!strncmp (option, "thread-dump-dir=", 16))
3773 mono_set_thread_dump_dir(g_strdup(option + 16));
3774 else if (!strncmp (option, "aot-skip=", 9)) {
3775 mini_debug_options.aot_skip_set = TRUE;
3776 mini_debug_options.aot_skip = atoi (option + 9);
3777 } else
3778 return FALSE;
3780 return TRUE;
3783 static void
3784 mini_parse_debug_options (void)
3786 char *options = g_getenv ("MONO_DEBUG");
3787 gchar **args, **ptr;
3789 if (!options)
3790 return;
3792 args = g_strsplit (options, ",", -1);
3793 g_free (options);
3795 for (ptr = args; ptr && *ptr; ptr++) {
3796 const char *arg = *ptr;
3798 if (!mini_parse_debug_option (arg)) {
3799 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3800 // test-tailcall-require is also accepted but not documented.
3801 // empty string is also accepted and ignored as a consequence
3802 // of appending ",foo" without checking for empty.
3803 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");
3804 exit (1);
3808 g_strfreev (args);
3811 MonoDebugOptions *
3812 mini_get_debug_options (void)
3814 return &mini_debug_options;
3817 static gpointer
3818 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3820 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3821 gpointer* desc = NULL;
3823 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3824 return desc;
3825 #if defined(__mono_ppc64__)
3826 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3828 desc [0] = addr;
3829 desc [1] = NULL;
3830 desc [2] = NULL;
3831 # endif
3832 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3833 return desc;
3834 #else
3835 return addr;
3836 #endif
3839 static gpointer
3840 mini_get_addr_from_ftnptr (gpointer descr)
3842 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3843 return *(gpointer*)descr;
3844 #else
3845 return descr;
3846 #endif
3849 static void
3850 register_jit_stats (void)
3852 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3853 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3854 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3855 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3856 mono_counters_register ("Methods using the interpreter", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_interp);
3857 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3858 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3859 mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
3860 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3861 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3862 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3863 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3864 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3865 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3866 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3867 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3868 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3869 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3870 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3871 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3872 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3873 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3874 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3875 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3876 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3877 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3878 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3879 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3880 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3881 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3882 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3883 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3884 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3885 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3886 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3887 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3888 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3889 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3890 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3891 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3892 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3893 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3894 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3895 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3896 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3897 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3898 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3899 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3900 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3901 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3902 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3903 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3904 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3905 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3906 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3907 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3908 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3909 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3910 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3911 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3912 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3913 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3916 static void runtime_invoke_info_free (gpointer value);
3918 static gint
3919 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3921 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3922 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3924 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3927 static guint
3928 class_method_pair_hash (gconstpointer data)
3930 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3932 return (gsize)pair->klass ^ (gsize)pair->method;
3935 static void
3936 mini_create_jit_domain_info (MonoDomain *domain)
3938 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3940 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3941 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3942 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3943 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3944 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3945 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3946 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3947 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3948 mono_jit_code_hash_init (&info->interp_code_hash);
3950 domain->runtime_info = info;
3953 static void
3954 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3956 MonoJumpList *jlist = (MonoJumpList *)value;
3957 g_slist_free (jlist->list);
3960 static void
3961 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3963 GSList *list = (GSList *)value;
3964 g_slist_free (list);
3967 static void
3968 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3970 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3971 mono_code_manager_destroy (di->code_mp);
3972 g_free (di);
3975 static void
3976 runtime_invoke_info_free (gpointer value)
3978 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3980 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3981 if (info->dyn_call_info)
3982 mono_arch_dyn_call_free (info->dyn_call_info);
3983 #endif
3984 g_free (info);
3987 static void
3988 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3990 g_slist_free (value);
3993 static void
3994 mini_free_jit_domain_info (MonoDomain *domain)
3996 MonoJitDomainInfo *info = domain_jit_info (domain);
3998 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3999 g_hash_table_destroy (info->jump_target_hash);
4000 if (info->jump_target_got_slot_hash) {
4001 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
4002 g_hash_table_destroy (info->jump_target_got_slot_hash);
4004 if (info->dynamic_code_hash) {
4005 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
4006 g_hash_table_destroy (info->dynamic_code_hash);
4008 g_hash_table_destroy (info->method_code_hash);
4009 g_hash_table_destroy (info->jump_trampoline_hash);
4010 g_hash_table_destroy (info->jit_trampoline_hash);
4011 g_hash_table_destroy (info->delegate_trampoline_hash);
4012 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
4013 g_hash_table_destroy (info->mrgctx_hash);
4014 g_hash_table_destroy (info->method_rgctx_hash);
4015 g_hash_table_destroy (info->interp_method_pointer_hash);
4016 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
4017 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
4018 g_hash_table_destroy (info->seq_points);
4019 g_hash_table_destroy (info->arch_seq_points);
4020 if (info->agent_info)
4021 mini_get_dbg_callbacks ()->free_domain_info (domain);
4022 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
4023 if (info->llvm_jit_callees) {
4024 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
4025 g_hash_table_destroy (info->llvm_jit_callees);
4027 mono_internal_hash_table_destroy (&info->interp_code_hash);
4028 #ifdef ENABLE_LLVM
4029 mono_llvm_free_domain_info (domain);
4030 #endif
4032 g_free (domain->runtime_info);
4033 domain->runtime_info = NULL;
4036 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4038 static void
4039 code_manager_chunk_new (void *chunk, int size)
4041 mono_arch_code_chunk_new (chunk, size);
4044 static void
4045 code_manager_chunk_destroy (void *chunk)
4047 mono_arch_code_chunk_destroy (chunk);
4050 #endif
4052 #ifdef ENABLE_LLVM
4053 static gboolean
4054 llvm_init_inner (void)
4056 if (!mono_llvm_load (NULL))
4057 return FALSE;
4059 mono_llvm_init ();
4060 return TRUE;
4062 #endif
4065 * mini_llvm_init:
4067 * Load and initialize LLVM support.
4068 * Return TRUE on success.
4070 gboolean
4071 mini_llvm_init (void)
4073 #ifdef ENABLE_LLVM
4074 static gboolean llvm_inited;
4075 static gboolean init_result;
4077 mono_loader_lock_if_inited ();
4078 if (!llvm_inited) {
4079 init_result = llvm_init_inner ();
4080 llvm_inited = TRUE;
4082 mono_loader_unlock_if_inited ();
4083 return init_result;
4084 #else
4085 return FALSE;
4086 #endif
4089 void
4090 mini_add_profiler_argument (const char *desc)
4092 if (!profile_options)
4093 profile_options = g_ptr_array_new ();
4095 g_ptr_array_add (profile_options, (gpointer) desc);
4099 static MonoEECallbacks interp_cbs = {0};
4101 void
4102 mini_install_interp_callbacks (MonoEECallbacks *cbs)
4104 memcpy (&interp_cbs, cbs, sizeof (MonoEECallbacks));
4107 MonoEECallbacks *
4108 mini_get_interp_callbacks (void)
4110 return &interp_cbs;
4113 static MonoDebuggerCallbacks dbg_cbs;
4115 void
4116 mini_install_dbg_callbacks (MonoDebuggerCallbacks *cbs)
4118 g_assert (cbs->version == MONO_DBG_CALLBACKS_VERSION);
4119 memcpy (&dbg_cbs, cbs, sizeof (MonoDebuggerCallbacks));
4122 MonoDebuggerCallbacks*
4123 mini_get_dbg_callbacks (void)
4125 return &dbg_cbs;
4129 mono_ee_api_version (void)
4131 return MONO_EE_API_VERSION;
4134 void
4135 mono_interp_entry_from_trampoline (gpointer ccontext, gpointer imethod)
4137 mini_get_interp_callbacks ()->entry_from_trampoline (ccontext, imethod);
4140 MonoDomain *
4141 mini_init (const char *filename, const char *runtime_version)
4143 ERROR_DECL (error);
4144 MonoDomain *domain;
4145 MonoRuntimeCallbacks callbacks;
4146 MonoThreadInfoRuntimeCallbacks ticallbacks;
4147 MonoCodeManagerCallbacks code_manager_callbacks;
4149 MONO_VES_INIT_BEGIN ();
4151 CHECKED_MONO_INIT ();
4153 #if defined(__linux__)
4154 if (access ("/proc/self/maps", F_OK) != 0) {
4155 g_print ("Mono requires /proc to be mounted.\n");
4156 exit (1);
4158 #endif
4160 mono_interp_stub_init ();
4161 #ifndef DISABLE_INTERPRETER
4162 if (mono_use_interpreter)
4163 mono_ee_interp_init (mono_interp_opts_string);
4164 #endif
4166 mono_debugger_agent_stub_init ();
4167 #ifndef DISABLE_SDB
4168 mono_debugger_agent_init ();
4169 #endif
4171 if (sdb_options)
4172 mini_get_dbg_callbacks ()->parse_options (sdb_options);
4174 mono_os_mutex_init_recursive (&jit_mutex);
4176 mono_cross_helpers_run ();
4178 mono_counters_init ();
4180 mini_jit_init ();
4182 mini_jit_init_job_control ();
4184 /* Happens when using the embedding interface */
4185 if (!default_opt_set)
4186 default_opt = mono_parse_default_optimizations (NULL);
4188 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4189 if (mono_aot_only)
4190 mono_set_generic_sharing_vt_supported (TRUE);
4191 #else
4192 if (mono_llvm_only)
4193 mono_set_generic_sharing_vt_supported (TRUE);
4194 #endif
4196 mono_tls_init_runtime_keys ();
4198 if (!global_codeman)
4199 global_codeman = mono_code_manager_new ();
4201 memset (&callbacks, 0, sizeof (callbacks));
4202 callbacks.create_ftnptr = mini_create_ftnptr;
4203 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
4204 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
4205 callbacks.set_cast_details = mono_set_cast_details;
4206 callbacks.debug_log = mini_get_dbg_callbacks ()->debug_log;
4207 callbacks.debug_log_is_enabled = mini_get_dbg_callbacks ()->debug_log_is_enabled;
4208 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
4209 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
4210 callbacks.imt_entry_inited = mini_imt_entry_inited;
4211 callbacks.init_delegate = mini_init_delegate;
4212 #define JIT_INVOKE_WORKS
4213 #ifdef JIT_INVOKE_WORKS
4214 callbacks.runtime_invoke = mono_jit_runtime_invoke;
4215 #endif
4216 #define JIT_TRAMPOLINES_WORK
4217 #ifdef JIT_TRAMPOLINES_WORK
4218 callbacks.compile_method = mono_jit_compile_method;
4219 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
4220 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
4221 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
4222 callbacks.free_method = mono_jit_free_method;
4223 #ifndef DISABLE_REMOTING
4224 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
4225 #endif
4226 #endif
4227 #ifndef DISABLE_REMOTING
4228 if (mono_use_interpreter)
4229 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
4230 #endif
4231 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
4233 #ifdef TARGET_OSX
4234 callbacks.install_state_summarizer = mini_register_sigterm_handler;
4235 #endif
4237 mono_install_callbacks (&callbacks);
4239 memset (&ticallbacks, 0, sizeof (ticallbacks));
4240 ticallbacks.setup_async_callback = mono_setup_async_callback;
4241 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
4242 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
4243 ticallbacks.thread_state_init = mono_thread_state_init;
4245 #ifndef HOST_WIN32
4246 mono_w32handle_init ();
4247 #endif
4249 mono_thread_info_runtime_init (&ticallbacks);
4251 if (g_hasenv ("MONO_DEBUG")) {
4252 mini_parse_debug_options ();
4255 mono_code_manager_init ();
4257 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
4258 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
4259 code_manager_callbacks.chunk_new = code_manager_chunk_new;
4260 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
4261 #endif
4262 mono_code_manager_install_callbacks (&code_manager_callbacks);
4264 mono_hwcap_init ();
4266 mono_arch_cpu_init ();
4268 mono_arch_init ();
4270 mono_unwind_init ();
4272 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
4273 mono_lldb_init ("");
4274 mono_dont_free_domains = TRUE;
4277 #ifdef XDEBUG_ENABLED
4278 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4279 if (mono_xdebug) {
4280 mono_xdebug_init (mono_xdebug);
4281 g_free (mono_xdebug);
4282 /* So methods for multiple domains don't have the same address */
4283 mono_dont_free_domains = TRUE;
4284 mono_using_xdebug = TRUE;
4285 } else if (mini_get_debug_options ()->gdb) {
4286 mono_xdebug_init ((char*)"gdb");
4287 mono_dont_free_domains = TRUE;
4288 mono_using_xdebug = TRUE;
4290 #endif
4292 #ifdef ENABLE_LLVM
4293 if (mono_use_llvm) {
4294 if (!mono_llvm_load (NULL)) {
4295 mono_use_llvm = FALSE;
4296 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4299 if (mono_use_llvm)
4300 mono_llvm_init ();
4301 #endif
4303 mono_trampolines_init ();
4305 if (default_opt & MONO_OPT_AOT)
4306 mono_aot_init ();
4308 mini_get_dbg_callbacks ()->init ();
4310 #ifdef TARGET_WASM
4311 mono_wasm_debugger_init ();
4312 #endif
4314 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4315 mono_set_generic_sharing_supported (TRUE);
4316 #endif
4318 mono_thread_info_signals_init ();
4320 #ifndef MONO_CROSS_COMPILE
4321 mono_runtime_install_handlers ();
4322 #endif
4323 mono_threads_install_cleanup (mini_thread_cleanup);
4325 #ifdef JIT_TRAMPOLINES_WORK
4326 mono_install_create_domain_hook (mini_create_jit_domain_info);
4327 mono_install_free_domain_hook (mini_free_jit_domain_info);
4328 #endif
4329 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4330 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4331 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4333 mono_profiler_state.context_enable = mini_profiler_context_enable;
4334 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4335 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4336 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4337 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4338 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4340 if (profile_options)
4341 for (guint i = 0; i < profile_options->len; i++)
4342 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4344 mono_profiler_started ();
4346 if (mini_debug_options.collect_pagefault_stats)
4347 mono_aot_set_make_unreadable (TRUE);
4349 if (runtime_version)
4350 domain = mono_init_version (filename, runtime_version);
4351 else
4352 domain = mono_init_from_assembly (filename, filename);
4354 if (mono_aot_only) {
4355 /* This helps catch code allocation requests */
4356 mono_code_manager_set_read_only (domain->code_mp);
4357 mono_marshal_use_aot_wrappers (TRUE);
4360 if (mono_llvm_only) {
4361 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
4362 mono_set_always_build_imt_trampolines (TRUE);
4363 } else if (mono_aot_only) {
4364 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4365 } else {
4366 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4369 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4370 mono_arch_finish_init ();
4372 mono_icall_init ();
4374 /* This must come after mono_init () in the aot-only case */
4375 mono_exceptions_init ();
4377 /* This should come after mono_init () too */
4378 mini_gc_init ();
4380 #ifndef DISABLE_JIT
4381 mono_create_helper_signatures ();
4382 #endif
4384 register_jit_stats ();
4386 #define JIT_CALLS_WORK
4387 #ifdef JIT_CALLS_WORK
4388 /* Needs to be called here since register_jit_icall depends on it */
4389 mono_marshal_init ();
4391 mono_arch_register_lowlevel_calls ();
4393 register_icalls ();
4395 mono_generic_sharing_init ();
4396 #endif
4398 #ifdef MONO_ARCH_SIMD_INTRINSICS
4399 mono_simd_intrinsics_init ();
4400 #endif
4402 mono_tasklets_init ();
4404 register_trampolines (domain);
4406 if (mono_compile_aot)
4408 * Avoid running managed code when AOT compiling, since the platform
4409 * might only support aot-only execution.
4411 mono_runtime_set_no_exec (TRUE);
4413 mono_mem_account_register_counters ();
4415 #define JIT_RUNTIME_WORKS
4416 #ifdef JIT_RUNTIME_WORKS
4417 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4418 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, error);
4419 mono_error_assert_ok (error);
4420 mono_thread_attach (domain);
4421 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4422 #endif
4424 if (mono_profiler_sampling_enabled ())
4425 mono_runtime_setup_stat_profiler ();
4427 MONO_PROFILER_RAISE (runtime_initialized, ());
4429 MONO_VES_INIT_END ();
4431 return domain;
4434 static void
4435 register_icalls (void)
4437 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4438 ves_icall_get_frame_info);
4439 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4440 ves_icall_get_trace);
4441 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4442 mono_runtime_install_handlers);
4443 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4444 mono_runtime_cleanup_handlers);
4446 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4447 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4448 mini_get_dbg_callbacks ()->unhandled_exception);
4449 #endif
4452 * It's important that we pass `TRUE` as the last argument here, as
4453 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4454 * *did* emit a wrapper, we'd be looking at infinite recursion since
4455 * the wrapper would call the icall which would call the wrapper and
4456 * so on.
4458 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4459 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4460 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4461 register_icall (mono_profiler_raise_exception_clause, "mono_profiler_raise_exception_clause", "void ptr int int object", TRUE);
4463 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4464 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4465 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4466 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4467 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4468 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4470 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4471 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4472 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4473 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4474 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4475 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4476 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4477 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4478 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4480 // FIXME: This is broken
4481 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4482 #endif
4484 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4485 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4486 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4487 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4488 register_icall (ves_icall_thread_finish_async_abort, "ves_icall_thread_finish_async_abort", "void", FALSE);
4489 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4490 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4492 if (mono_threads_are_safepoints_enabled ())
4493 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4495 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4496 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4497 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4498 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4499 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4500 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4501 #endif
4502 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4503 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4504 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4505 #endif
4507 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4508 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4509 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4510 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4511 #endif
4513 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4514 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4515 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4516 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4517 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4518 #endif
4520 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4521 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4522 #endif
4524 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4525 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4526 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4527 #endif
4529 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4530 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4531 #endif
4533 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4534 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4535 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4536 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4537 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4538 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4539 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4542 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4543 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4544 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4545 #endif
4547 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4548 register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);
4549 #endif
4550 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4551 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4552 #endif
4553 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4554 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4555 #endif
4556 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4557 register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
4558 #endif
4559 #ifdef MONO_ARCH_EMULATE_FREM
4560 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4561 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4562 #endif
4564 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4565 if (mono_arch_is_soft_float ()) {
4566 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4567 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4568 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4569 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4570 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4571 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4572 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4573 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4574 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4575 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4576 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4577 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4579 #if SIZEOF_VOID_P == 4
4580 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4581 #endif
4583 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4584 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4585 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4586 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4587 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4588 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4589 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4590 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4591 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4592 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4594 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4595 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4596 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4597 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4598 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4600 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4601 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4602 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4603 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4605 #endif
4606 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4608 #ifdef COMPRESSED_INTERFACE_BITMAP
4609 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4610 #endif
4612 #if SIZEOF_REGISTER == 4
4613 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4614 #else
4615 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4616 #endif
4618 /* other jit icalls */
4619 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4620 register_icall (ves_icall_mono_delegate_ctor_interp, "ves_icall_mono_delegate_ctor_interp", "void object object ptr", FALSE);
4621 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4622 "ptr ptr ptr", FALSE);
4623 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4624 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4625 "ptr ptr ptr ptr", FALSE);
4626 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4627 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4628 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4629 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4630 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4631 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4632 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4633 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4634 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4635 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4636 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4637 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4638 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4639 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4640 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4641 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4642 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4643 register_icall (mono_break, "mono_break", NULL, TRUE);
4644 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4645 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4646 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4647 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4648 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4649 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4650 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4651 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4652 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4653 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4654 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4656 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4657 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4659 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4660 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4661 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4662 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4663 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4665 register_icall (mini_get_dbg_callbacks ()->user_break, "mono_debugger_agent_user_break", "void", FALSE);
4667 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4668 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4669 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4670 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4672 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4673 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4674 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4675 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4676 /* This needs a wrapper so it can have a preserveall cconv */
4677 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4678 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4679 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4680 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4681 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4682 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4683 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4685 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "int32 obj");
4686 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4687 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4688 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4690 #ifdef TARGET_IOS
4691 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4692 #endif
4693 /* Register tls icalls */
4694 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4695 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4696 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4697 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4698 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4699 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4700 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4701 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4702 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4703 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4705 register_icall_no_wrapper (mono_interp_entry_from_trampoline, "mono_interp_entry_from_trampoline", "void ptr ptr");
4707 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4708 mono_arch_register_icall ();
4709 #endif
4712 MonoJitStats mono_jit_stats = {0};
4715 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4716 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4718 MONO_NO_SANITIZE_THREAD
4719 static void
4720 print_jit_stats (void)
4722 if (mono_jit_stats.enabled) {
4723 g_print ("Mono Jit statistics\n");
4724 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4725 mono_jit_stats.max_ratio_method);
4726 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4727 mono_jit_stats.biggest_method);
4729 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4730 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4731 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4732 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4733 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4734 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4735 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4736 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4738 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4739 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4740 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4742 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4743 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4744 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4745 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4747 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4748 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4749 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4750 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4751 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4752 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4753 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4754 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4756 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4757 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4758 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4760 g_free (mono_jit_stats.max_ratio_method);
4761 mono_jit_stats.max_ratio_method = NULL;
4762 g_free (mono_jit_stats.biggest_method);
4763 mono_jit_stats.biggest_method = NULL;
4767 void
4768 mini_cleanup (MonoDomain *domain)
4770 if (mono_profiler_sampling_enabled ())
4771 mono_runtime_shutdown_stat_profiler ();
4773 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4775 #ifndef DISABLE_COM
4776 mono_cominterop_release_all_rcws ();
4777 #endif
4779 #ifndef MONO_CROSS_COMPILE
4781 * mono_domain_finalize () needs to be called early since it needs the
4782 * execution engine still fully working (it may invoke managed finalizers).
4784 mono_domain_finalize (domain, 2000);
4785 #endif
4787 /* This accesses metadata so needs to be called before runtime shutdown */
4788 print_jit_stats ();
4790 #ifndef MONO_CROSS_COMPILE
4791 mono_runtime_cleanup (domain);
4792 #endif
4794 mono_threadpool_cleanup ();
4796 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4798 mono_profiler_cleanup ();
4800 if (profile_options)
4801 g_ptr_array_free (profile_options, TRUE);
4803 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4805 mono_icall_cleanup ();
4807 mono_runtime_cleanup_handlers ();
4809 #ifndef MONO_CROSS_COMPILE
4810 mono_domain_free (domain, TRUE);
4811 #endif
4813 #ifdef ENABLE_LLVM
4814 if (mono_use_llvm)
4815 mono_llvm_cleanup ();
4816 #endif
4818 mono_aot_cleanup ();
4820 mono_trampolines_cleanup ();
4822 mono_unwind_cleanup ();
4824 mono_code_manager_destroy (global_codeman);
4825 g_free (vtable_trampolines);
4827 mini_jit_cleanup ();
4829 mono_tramp_info_cleanup ();
4831 mono_arch_cleanup ();
4833 mono_generic_sharing_cleanup ();
4835 mono_cleanup ();
4837 mono_trace_cleanup ();
4839 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4841 if (mono_inject_async_exc_method)
4842 mono_method_desc_free (mono_inject_async_exc_method);
4844 mono_tls_free_keys ();
4846 mono_os_mutex_destroy (&jit_mutex);
4848 mono_code_manager_cleanup ();
4850 #ifndef HOST_WIN32
4851 mono_w32handle_cleanup ();
4852 #endif
4855 void
4856 mono_set_defaults (int verbose_level, guint32 opts)
4858 mini_verbose = verbose_level;
4859 mono_set_optimizations (opts);
4862 void
4863 mono_disable_optimizations (guint32 opts)
4865 default_opt &= ~opts;
4868 void
4869 mono_set_optimizations (guint32 opts)
4871 default_opt = opts;
4872 default_opt_set = TRUE;
4873 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4874 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4875 #else
4876 if (mono_llvm_only)
4877 mono_set_generic_sharing_vt_supported (TRUE);
4878 #endif
4881 void
4882 mono_set_verbose_level (guint32 level)
4884 mini_verbose = level;
4888 * mono_get_runtime_build_info:
4889 * The returned string is owned by the caller. The returned string
4890 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4891 * \returns the runtime version + build date in string format.
4893 char*
4894 mono_get_runtime_build_info (void)
4896 if (mono_build_date)
4897 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4898 else
4899 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4902 static void
4903 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4905 GHashTable *assemblies = (GHashTable*)user_data;
4906 MonoImage *image = mono_assembly_get_image (ass);
4907 MonoMethod *method, *invoke;
4908 int i, count = 0;
4910 if (g_hash_table_lookup (assemblies, ass))
4911 return;
4913 g_hash_table_insert (assemblies, ass, ass);
4915 if (mini_verbose > 0)
4916 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4918 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4919 ERROR_DECL (error);
4921 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
4922 if (!method) {
4923 mono_error_cleanup (error); /* FIXME don't swallow the error */
4924 continue;
4926 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4927 continue;
4928 if (method->is_generic || mono_class_is_gtd (method->klass))
4929 continue;
4931 count++;
4932 if (mini_verbose > 1) {
4933 char * desc = mono_method_full_name (method, TRUE);
4934 g_print ("Compiling %d %s\n", count, desc);
4935 g_free (desc);
4937 mono_compile_method_checked (method, error);
4938 if (!is_ok (error)) {
4939 mono_error_cleanup (error); /* FIXME don't swallow the error */
4940 continue;
4942 if (strcmp (method->name, "Finalize") == 0) {
4943 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4944 mono_compile_method_checked (invoke, error);
4945 mono_error_assert_ok (error);
4947 #ifndef DISABLE_REMOTING
4948 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4949 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
4950 mono_error_assert_ok (error);
4951 mono_compile_method_checked (invoke, error);
4952 mono_error_assert_ok (error);
4954 #endif
4957 /* Load and precompile referenced assemblies as well */
4958 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4959 mono_assembly_load_reference (image, i);
4960 if (image->references [i])
4961 mono_precompile_assembly (image->references [i], assemblies);
4965 void mono_precompile_assemblies ()
4967 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4969 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4971 g_hash_table_destroy (assemblies);
4975 * Used by LLVM.
4976 * Have to export this for AOT.
4978 void
4979 mono_personality (void)
4981 /* Not used */
4982 g_assert_not_reached ();
4986 static MonoBreakPolicy
4987 always_insert_breakpoint (MonoMethod *method)
4989 return MONO_BREAK_POLICY_ALWAYS;
4992 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4995 * mono_set_break_policy:
4996 * \param policy_callback the new callback function
4998 * Allow embedders to decide whether to actually obey breakpoint instructions
4999 * (both break IL instructions and \c Debugger.Break method calls), for example
5000 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5001 * untrusted or semi-trusted code.
5003 * \p policy_callback will be called every time a break point instruction needs to
5004 * be inserted with the method argument being the method that calls \c Debugger.Break
5005 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
5006 * if it wants the breakpoint to not be effective in the given method.
5007 * \c MONO_BREAK_POLICY_ALWAYS is the default.
5009 void
5010 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5012 if (policy_callback)
5013 break_policy_func = policy_callback;
5014 else
5015 break_policy_func = always_insert_breakpoint;
5018 gboolean
5019 mini_should_insert_breakpoint (MonoMethod *method)
5021 switch (break_policy_func (method)) {
5022 case MONO_BREAK_POLICY_ALWAYS:
5023 return TRUE;
5024 case MONO_BREAK_POLICY_NEVER:
5025 return FALSE;
5026 case MONO_BREAK_POLICY_ON_DBG:
5027 g_warning ("mdb no longer supported");
5028 return FALSE;
5029 default:
5030 g_warning ("Incorrect value returned from break policy callback");
5031 return FALSE;
5035 // Custom handlers currently only implemented by Windows.
5036 #ifndef HOST_WIN32
5037 gboolean
5038 mono_runtime_install_custom_handlers (const char *handlers)
5040 return FALSE;
5043 void
5044 mono_runtime_install_custom_handlers_usage (void)
5046 fprintf (stdout,
5047 "Custom Handlers:\n"
5048 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
5049 " separated list of available handlers to install.\n"
5050 "\n"
5051 "No handlers supported on current platform.\n");
5053 #endif /* HOST_WIN32 */