[interp] Allocate ThreadContext structures on the heap instead of on the stack, the...
[mono-project.git] / mono / mini / mini-runtime.c
blob7b80dc6b454c2a9a1350783e569bc79d6f2b40f3
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;
108 const char *mono_build_date;
109 gboolean mono_do_signal_chaining;
110 gboolean mono_do_crash_chaining;
111 int mini_verbose = 0;
114 * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
115 * it can load AOT code compiled by LLVM.
117 gboolean mono_use_llvm = FALSE;
119 gboolean mono_use_interpreter = FALSE;
120 const char *mono_interp_opts_string = NULL;
122 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
123 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
124 static mono_mutex_t jit_mutex;
126 static MonoCodeManager *global_codeman;
128 MonoDebugOptions mini_debug_options;
130 #ifdef VALGRIND_JIT_REGISTER_MAP
131 int valgrind_register;
132 #endif
133 GList* mono_aot_paths;
135 static GPtrArray *profile_options;
137 static GSList *tramp_infos;
139 static void register_icalls (void);
141 gboolean
142 mono_running_on_valgrind (void)
144 #ifndef HOST_WIN32
145 if (RUNNING_ON_VALGRIND){
146 #ifdef VALGRIND_JIT_REGISTER_MAP
147 valgrind_register = TRUE;
148 #endif
149 return TRUE;
150 } else
151 #endif
152 return FALSE;
155 typedef struct {
156 void *ip;
157 MonoMethod *method;
158 } FindTrampUserData;
160 static void
161 find_tramp (gpointer key, gpointer value, gpointer user_data)
163 FindTrampUserData *ud = (FindTrampUserData*)user_data;
165 if (value == ud->ip)
166 ud->method = (MonoMethod*)key;
169 /* debug function */
170 G_GNUC_UNUSED static char*
171 get_method_from_ip (void *ip)
173 MonoJitInfo *ji;
174 MonoMethod *method;
175 char *method_name;
176 char *res;
177 MonoDomain *domain = mono_domain_get ();
178 MonoDebugSourceLocation *location;
179 FindTrampUserData user_data;
181 if (!domain)
182 domain = mono_get_root_domain ();
184 ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
185 if (!ji) {
186 user_data.ip = ip;
187 user_data.method = NULL;
188 mono_domain_lock (domain);
189 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
190 mono_domain_unlock (domain);
191 if (user_data.method) {
192 char *mname = mono_method_full_name (user_data.method, TRUE);
193 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
194 g_free (mname);
195 return res;
197 else
198 return NULL;
199 } else if (ji->is_trampoline) {
200 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
201 return res;
204 method = jinfo_get_method (ji);
205 method_name = mono_method_full_name (method, TRUE);
206 /* FIXME: unused ? */
207 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
209 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);
211 mono_debug_free_source_location (location);
212 g_free (method_name);
214 return res;
218 * mono_pmip:
219 * \param ip an instruction pointer address
221 * This method is used from a debugger to get the name of the
222 * method at address \p ip. This routine is typically invoked from
223 * a debugger like this:
225 * (gdb) print mono_pmip ($pc)
227 * \returns the name of the method at address \p ip.
229 G_GNUC_UNUSED char *
230 mono_pmip (void *ip)
232 return get_method_from_ip (ip);
236 * mono_print_method_from_ip:
237 * \param ip an instruction pointer address
239 * This method is used from a debugger to get the name of the
240 * method at address \p ip.
242 * This prints the name of the method at address \p ip in the standard
243 * output. Unlike \c mono_pmip which returns a string, this routine
244 * prints the value on the standard output.
246 MONO_ATTR_USED void
247 mono_print_method_from_ip (void *ip)
249 MonoJitInfo *ji;
250 char *method;
251 MonoDebugSourceLocation *source;
252 MonoDomain *domain = mono_domain_get ();
253 MonoDomain *target_domain = mono_domain_get ();
254 FindTrampUserData user_data;
255 MonoGenericSharingContext*gsctx;
256 const char *shared_type;
258 if (!domain)
259 domain = mono_get_root_domain ();
260 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
261 if (ji && ji->is_trampoline) {
262 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
264 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
265 return;
268 if (!ji) {
269 user_data.ip = ip;
270 user_data.method = NULL;
271 mono_domain_lock (domain);
272 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
273 mono_domain_unlock (domain);
275 if (user_data.method) {
276 char *mname = mono_method_full_name (user_data.method, TRUE);
277 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
278 g_free (mname);
279 return;
282 g_print ("No method at %p\n", ip);
283 fflush (stdout);
284 return;
286 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
287 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
289 gsctx = mono_jit_info_get_generic_sharing_context (ji);
290 shared_type = "";
291 if (gsctx) {
292 if (gsctx->is_gsharedvt)
293 shared_type = "gsharedvt ";
294 else
295 shared_type = "gshared ";
298 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);
300 if (source)
301 g_print ("%s:%d\n", source->source_file, source->row);
302 fflush (stdout);
304 mono_debug_free_source_location (source);
305 g_free (method);
309 * mono_method_same_domain:
311 * Determine whenever two compiled methods are in the same domain, thus
312 * the address of the callee can be embedded in the caller.
314 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
316 MonoMethod *cmethod;
318 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
319 return FALSE;
322 * If the call was made from domain-neutral to domain-specific
323 * code, we can't patch the call site.
325 if (caller->domain_neutral && !callee->domain_neutral)
326 return FALSE;
328 cmethod = jinfo_get_method (caller);
329 if ((cmethod->klass == mono_defaults.appdomain_class) &&
330 (strstr (cmethod->name, "InvokeInDomain"))) {
331 /* The InvokeInDomain methods change the current appdomain */
332 return FALSE;
335 return TRUE;
339 * mono_global_codeman_reserve:
341 * Allocate code memory from the global code manager.
343 void *mono_global_codeman_reserve (int size)
345 void *ptr;
347 if (mono_aot_only)
348 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
350 if (!global_codeman) {
351 /* This can happen during startup */
352 global_codeman = mono_code_manager_new ();
353 return mono_code_manager_reserve (global_codeman, size);
355 else {
356 mono_jit_lock ();
357 ptr = mono_code_manager_reserve (global_codeman, size);
358 mono_jit_unlock ();
359 return ptr;
363 /* The callback shouldn't take any locks */
364 void
365 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
367 mono_jit_lock ();
368 mono_code_manager_foreach (global_codeman, func, user_data);
369 mono_jit_unlock ();
373 * mono_create_unwind_op:
375 * Create an unwind op with the given parameters.
377 MonoUnwindOp*
378 mono_create_unwind_op (int when, int tag, int reg, int val)
380 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
382 op->op = tag;
383 op->reg = reg;
384 op->val = val;
385 op->when = when;
387 return op;
390 MonoJumpInfoToken *
391 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
393 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
394 res->image = image;
395 res->token = token;
396 res->has_context = context != NULL;
397 if (context)
398 memcpy (&res->context, context, sizeof (MonoGenericContext));
400 return res;
403 MonoJumpInfoToken *
404 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
406 return mono_jump_info_token_new2 (mp, image, token, NULL);
410 * mono_tramp_info_create:
412 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
413 * of JI, and UNWIND_OPS.
415 MonoTrampInfo*
416 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
418 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
420 info->name = g_strdup ((char*)name);
421 info->code = code;
422 info->code_size = code_size;
423 info->ji = ji;
424 info->unwind_ops = unwind_ops;
426 return info;
429 void
430 mono_tramp_info_free (MonoTrampInfo *info)
432 g_free (info->name);
434 // FIXME: ji
435 mono_free_unwind_info (info->unwind_ops);
436 if (info->owns_uw_info)
437 g_free (info->uw_info);
438 g_free (info);
441 static void
442 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
444 MonoJitInfo *ji;
446 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
447 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
448 ji->d.tramp_info = info;
449 ji->is_trampoline = TRUE;
451 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
453 mono_jit_info_table_add (domain, ji);
457 * mono_tramp_info_register:
459 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
460 * INFO can be NULL.
461 * Frees INFO.
463 static void
464 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
466 MonoTrampInfo *copy;
468 if (!info)
469 return;
471 if (!domain)
472 domain = mono_get_root_domain ();
474 if (domain)
475 copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
476 else
477 copy = g_new0 (MonoTrampInfo, 1);
479 copy->code = info->code;
480 copy->code_size = info->code_size;
481 copy->name = g_strdup (info->name);
483 if (info->unwind_ops) {
484 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
485 copy->owns_uw_info = TRUE;
486 if (domain) {
487 /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
488 guint8 *temp = copy->uw_info;
489 copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
490 memcpy (copy->uw_info, temp, copy->uw_info_len);
491 g_free (temp);
493 } else {
494 /* Trampolines from aot have the unwind ops already encoded */
495 copy->uw_info = info->uw_info;
496 copy->uw_info_len = info->uw_info_len;
499 mono_save_trampoline_xdebug_info (info);
500 mono_lldb_save_trampoline_info (info);
502 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
503 if (!aot)
504 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
505 #endif
507 if (!domain) {
508 /* If no root domain has been created yet, postpone the registration. */
509 mono_jit_lock ();
510 tramp_infos = g_slist_prepend (tramp_infos, copy);
511 mono_jit_unlock ();
512 } else if (copy->uw_info) {
513 /* Only register trampolines that have unwind infos */
514 register_trampoline_jit_info (domain, copy);
517 if (mono_jit_map_is_enabled ())
518 mono_emit_jit_tramp (info->code, info->code_size, info->name);
520 mono_tramp_info_free (info);
523 void
524 mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
526 mono_tramp_info_register_internal (info, domain, FALSE);
529 void
530 mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
532 mono_tramp_info_register_internal (info, domain, TRUE);
535 static void
536 mono_tramp_info_cleanup (void)
538 GSList *l;
540 for (l = tramp_infos; l; l = l->next) {
541 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
543 mono_tramp_info_free (info);
545 g_slist_free (tramp_infos);
548 /* Register trampolines created before the root domain was created in the jit info tables */
549 static void
550 register_trampolines (MonoDomain *domain)
552 GSList *l;
554 for (l = tramp_infos; l; l = l->next) {
555 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
557 register_trampoline_jit_info (domain, info);
561 G_GNUC_UNUSED static void
562 break_count (void)
567 * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
568 * Set a breakpoint in break_count () to break the last time <x> is done.
570 G_GNUC_UNUSED gboolean
571 mono_debug_count (void)
573 static int count = 0, int_val = 0;
574 static gboolean inited, has_value = FALSE;
576 count ++;
578 if (!inited) {
579 char *value = g_getenv ("COUNT");
580 if (value) {
581 int_val = atoi (value);
582 g_free (value);
583 has_value = TRUE;
585 inited = TRUE;
588 if (!has_value)
589 return TRUE;
591 if (count == int_val)
592 break_count ();
594 if (count > int_val)
595 return FALSE;
597 return TRUE;
600 gconstpointer
601 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
603 ERROR_DECL (error);
604 char *name;
605 MonoMethod *wrapper;
606 gconstpointer trampoline;
607 MonoDomain *domain = mono_get_root_domain ();
608 gboolean check_exc = TRUE;
610 if (callinfo->wrapper)
611 return callinfo->wrapper;
613 if (callinfo->trampoline)
614 return callinfo->trampoline;
616 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
617 /* This icall is used to check for exceptions, so don't check in the wrapper */
618 check_exc = FALSE;
620 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
621 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
622 g_free (name);
624 if (do_compile) {
625 trampoline = mono_compile_method_checked (wrapper, error);
626 mono_error_assert_ok (error);
627 } else {
629 trampoline = mono_create_jit_trampoline (domain, wrapper, error);
630 mono_error_assert_ok (error);
631 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
634 mono_loader_lock ();
635 if (!callinfo->trampoline) {
636 mono_register_jit_icall_wrapper (callinfo, trampoline);
637 callinfo->trampoline = trampoline;
639 mono_loader_unlock ();
641 return callinfo->trampoline;
644 gconstpointer
645 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
647 return mono_icall_get_wrapper_full (callinfo, FALSE);
650 static MonoJitDynamicMethodInfo*
651 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
653 MonoJitDynamicMethodInfo *res;
655 if (domain_jit_info (domain)->dynamic_code_hash)
656 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
657 else
658 res = NULL;
659 return res;
662 static void
663 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_wrapper)
665 #ifndef DISABLE_JIT
666 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_wrapper);
667 #else
668 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
670 g_assert (!sig->hasthis);
671 g_assert (sig->param_count < 3);
673 mono_register_jit_icall_full (func, name, sig, no_wrapper, symbol);
674 #endif
678 * For JIT icalls implemented in C.
679 * NAME should be the same as the name of the C function whose address is FUNC.
680 * If @avoid_wrapper is TRUE, no wrapper is generated. This is for perf critical icalls which
681 * can't throw exceptions.
683 static void
684 register_icall (gpointer func, const char *name, const char *sigstr, gboolean avoid_wrapper)
686 MonoMethodSignature *sig;
688 if (sigstr)
689 sig = mono_create_icall_signature (sigstr);
690 else
691 sig = NULL;
693 mono_register_jit_icall_full (func, name, sig, avoid_wrapper, avoid_wrapper ? name : NULL);
696 static void
697 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
699 MonoMethodSignature *sig;
701 if (sigstr)
702 sig = mono_create_icall_signature (sigstr);
703 else
704 sig = NULL;
706 mono_register_jit_icall_full (func, name, sig, TRUE, name);
709 static void
710 register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
712 MonoMethodSignature *sig;
714 if (sigstr)
715 sig = mono_create_icall_signature (sigstr);
716 else
717 sig = NULL;
719 mono_register_jit_icall_full (func, name, sig, FALSE, NULL);
722 static void
723 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
725 MonoMethodSignature *sig;
727 if (sigstr)
728 sig = mono_create_icall_signature (sigstr);
729 else
730 sig = NULL;
732 mono_register_jit_icall (func, name, sig, save);
735 MonoLMF *
736 mono_get_lmf (void)
738 MonoJitTlsData *jit_tls;
740 if ((jit_tls = mono_tls_get_jit_tls ()))
741 return jit_tls->lmf;
743 * We do not assert here because this function can be called from
744 * mini-gc.c on a thread that has not executed any managed code, yet
745 * (the thread object allocation can trigger a collection).
747 return NULL;
750 MonoLMF **
751 mono_get_lmf_addr (void)
753 return (MonoLMF **)mono_tls_get_lmf_addr ();
756 void
757 mono_set_lmf (MonoLMF *lmf)
759 (*mono_get_lmf_addr ()) = lmf;
762 MonoJitTlsData*
763 mono_get_jit_tls (void)
765 return (MonoJitTlsData *)mono_tls_get_jit_tls ();
768 static void
769 mono_set_jit_tls (MonoJitTlsData *jit_tls)
771 MonoThreadInfo *info;
773 mono_tls_set_jit_tls (jit_tls);
775 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
776 info = mono_thread_info_current ();
777 if (info)
778 mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
781 static void
782 mono_set_lmf_addr (gpointer lmf_addr)
784 MonoThreadInfo *info;
786 mono_tls_set_lmf_addr (lmf_addr);
788 /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
789 info = mono_thread_info_current ();
790 if (info)
791 mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
795 * mono_push_lmf:
797 * Push an MonoLMFExt frame on the LMF stack.
799 void
800 mono_push_lmf (MonoLMFExt *ext)
802 MonoLMF **lmf_addr;
804 lmf_addr = mono_get_lmf_addr ();
806 ext->lmf.previous_lmf = *lmf_addr;
807 /* Mark that this is a MonoLMFExt */
808 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
810 mono_set_lmf ((MonoLMF*)ext);
814 * mono_pop_lmf:
816 * Pop the last frame from the LMF stack.
818 void
819 mono_pop_lmf (MonoLMF *lmf)
821 mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
825 * mono_jit_thread_attach:
827 * Called by Xamarin.Mac and other products. Attach thread to runtime if
828 * needed and switch to @domain.
830 * @return the original domain which needs to be restored, or NULL.
832 MonoDomain*
833 mono_jit_thread_attach (MonoDomain *domain)
835 MonoDomain *orig;
836 gboolean attached;
838 g_assert (!mono_threads_is_blocking_transition_enabled ());
840 if (!domain) {
841 /* Happens when called from AOTed code which is only used in the root domain. */
842 domain = mono_get_root_domain ();
845 g_assert (domain);
847 attached = mono_tls_get_jit_tls () != NULL;
849 if (!attached) {
850 mono_thread_attach (domain);
852 // #678164
853 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
856 orig = mono_domain_get ();
857 if (orig != domain)
858 mono_domain_set (domain, TRUE);
860 return orig != domain ? orig : NULL;
864 * mono_jit_set_domain:
866 * Set domain to @domain if @domain is not null
868 void
869 mono_jit_set_domain (MonoDomain *domain)
871 g_assert (!mono_threads_is_blocking_transition_enabled ());
873 if (domain)
874 mono_domain_set (domain, TRUE);
878 * mono_thread_abort:
879 * \param obj exception object
880 * Abort the thread, print exception information and stack trace
882 static void
883 mono_thread_abort (MonoObject *obj)
885 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
887 /* handle_remove should be eventually called for this thread, too
888 g_free (jit_tls);*/
890 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
891 (obj->vtable->klass == mono_defaults.threadabortexception_class) ||
892 ((obj->vtable->klass) == mono_class_get_appdomain_unloaded_exception_class () &&
893 mono_thread_info_current ()->runtime_thread)) {
894 mono_thread_exit ();
895 } else {
896 mono_invoke_unhandled_exception_hook (obj);
900 static void*
901 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
903 MonoJitTlsData *jit_tls;
904 MonoLMF *lmf;
906 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
907 if (jit_tls)
908 return jit_tls;
910 jit_tls = g_new0 (MonoJitTlsData, 1);
912 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
913 jit_tls->end_of_stack = stack_start;
915 mono_set_jit_tls (jit_tls);
917 lmf = g_new0 (MonoLMF, 1);
918 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
920 jit_tls->first_lmf = lmf;
922 mono_set_lmf_addr (&jit_tls->lmf);
924 jit_tls->lmf = lmf;
926 #ifdef MONO_ARCH_HAVE_TLS_INIT
927 mono_arch_tls_init ();
928 #endif
930 mono_setup_altstack (jit_tls);
932 return jit_tls;
935 static void
936 free_jit_tls_data (MonoJitTlsData *jit_tls)
938 mono_arch_free_jit_tls_data (jit_tls);
939 mono_free_altstack (jit_tls);
941 g_free (jit_tls->first_lmf);
942 g_free (jit_tls->interp_context);
943 g_free (jit_tls);
946 static void
947 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
949 MonoThreadInfo *thread;
950 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
951 thread = mono_thread_info_current_unchecked ();
952 if (thread)
953 thread->jit_data = jit_tls;
955 mono_arch_cpu_init ();
958 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
960 static void
961 mono_thread_abort_dummy (MonoObject *obj)
963 if (mono_thread_attach_aborted_cb)
964 mono_thread_attach_aborted_cb (obj);
965 else
966 mono_thread_abort (obj);
969 static void
970 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
972 MonoThreadInfo *thread;
973 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
974 thread = mono_thread_info_current_unchecked ();
975 if (thread)
976 thread->jit_data = jit_tls;
978 mono_arch_cpu_init ();
981 static void
982 mini_thread_cleanup (MonoNativeThreadId tid)
984 MonoJitTlsData *jit_tls = NULL;
985 MonoThreadInfo *info;
987 info = mono_thread_info_current_unchecked ();
989 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
990 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
991 * not a trivial thing.
993 * The current offender is mono_thread_manage which cleanup threads from the outside.
995 if (info && mono_thread_info_get_tid (info) == tid) {
996 jit_tls = (MonoJitTlsData *)info->jit_data;
997 info->jit_data = NULL;
999 mono_set_jit_tls (NULL);
1001 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
1002 if (mono_get_lmf ()) {
1003 mono_set_lmf (NULL);
1004 mono_set_lmf_addr (NULL);
1006 } else {
1007 info = mono_thread_info_lookup (tid);
1008 if (info) {
1009 jit_tls = (MonoJitTlsData *)info->jit_data;
1010 info->jit_data = NULL;
1012 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1015 if (jit_tls)
1016 free_jit_tls_data (jit_tls);
1019 MonoJumpInfo *
1020 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
1022 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
1024 ji->ip.i = ip;
1025 ji->type = type;
1026 ji->data.target = target;
1027 ji->next = list;
1029 return ji;
1032 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1034 static const char* const patch_info_str[] = {
1035 #define PATCH_INFO(a,b) "" #a,
1036 #include "patch-info.h"
1037 #undef PATCH_INFO
1040 const char*
1041 mono_ji_type_to_string (MonoJumpInfoType type)
1043 return patch_info_str [type];
1046 void
1047 mono_print_ji (const MonoJumpInfo *ji)
1049 switch (ji->type) {
1050 case MONO_PATCH_INFO_RGCTX_FETCH: {
1051 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1053 printf ("[RGCTX_FETCH ");
1054 mono_print_ji (entry->data);
1055 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1056 break;
1058 case MONO_PATCH_INFO_METHODCONST: {
1059 char *s = mono_method_full_name (ji->data.method, TRUE);
1060 printf ("[METHODCONST - %s]", s);
1061 g_free (s);
1062 break;
1064 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1065 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1066 break;
1068 default:
1069 printf ("[%s]", patch_info_str [ji->type]);
1070 break;
1074 #else
1076 const char*
1077 mono_ji_type_to_string (MonoJumpInfoType type)
1079 return "";
1082 void
1083 mono_print_ji (const MonoJumpInfo *ji)
1087 #endif
1090 * mono_patch_info_dup_mp:
1092 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1094 MonoJumpInfo*
1095 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1097 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1098 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1100 switch (patch_info->type) {
1101 case MONO_PATCH_INFO_RVA:
1102 case MONO_PATCH_INFO_LDSTR:
1103 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1104 case MONO_PATCH_INFO_LDTOKEN:
1105 case MONO_PATCH_INFO_DECLSEC:
1106 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1107 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1108 break;
1109 case MONO_PATCH_INFO_SWITCH:
1110 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1111 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1112 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1113 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1114 break;
1115 case MONO_PATCH_INFO_RGCTX_FETCH:
1116 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1117 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1118 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1119 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1120 break;
1121 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1122 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1123 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1124 break;
1125 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1126 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1127 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1128 break;
1129 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1130 MonoGSharedVtMethodInfo *info;
1131 MonoGSharedVtMethodInfo *oinfo;
1132 int i;
1134 oinfo = patch_info->data.gsharedvt_method;
1135 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1136 res->data.gsharedvt_method = info;
1137 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1138 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1139 for (i = 0; i < oinfo->num_entries; ++i) {
1140 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1141 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1143 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1145 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1146 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1147 break;
1149 case MONO_PATCH_INFO_VIRT_METHOD: {
1150 MonoJumpInfoVirtMethod *info;
1151 MonoJumpInfoVirtMethod *oinfo;
1153 oinfo = patch_info->data.virt_method;
1154 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1155 res->data.virt_method = info;
1156 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1157 break;
1159 default:
1160 break;
1163 return res;
1166 guint
1167 mono_patch_info_hash (gconstpointer data)
1169 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1171 switch (ji->type) {
1172 case MONO_PATCH_INFO_RVA:
1173 case MONO_PATCH_INFO_LDSTR:
1174 case MONO_PATCH_INFO_LDTOKEN:
1175 case MONO_PATCH_INFO_DECLSEC:
1176 return (ji->type << 8) | ji->data.token->token;
1177 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1178 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1179 case MONO_PATCH_INFO_INTERNAL_METHOD:
1180 return (ji->type << 8) | g_str_hash (ji->data.name);
1181 case MONO_PATCH_INFO_VTABLE:
1182 case MONO_PATCH_INFO_CLASS:
1183 case MONO_PATCH_INFO_IID:
1184 case MONO_PATCH_INFO_ADJUSTED_IID:
1185 case MONO_PATCH_INFO_METHODCONST:
1186 case MONO_PATCH_INFO_METHOD:
1187 case MONO_PATCH_INFO_METHOD_JUMP:
1188 case MONO_PATCH_INFO_IMAGE:
1189 case MONO_PATCH_INFO_ICALL_ADDR:
1190 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1191 case MONO_PATCH_INFO_FIELD:
1192 case MONO_PATCH_INFO_SFLDA:
1193 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1194 case MONO_PATCH_INFO_METHOD_RGCTX:
1195 case MONO_PATCH_INFO_SIGNATURE:
1196 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1197 case MONO_PATCH_INFO_AOT_JIT_INFO:
1198 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1199 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1200 return (ji->type << 8) | (gssize)ji->data.target;
1201 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1202 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1203 case MONO_PATCH_INFO_RGCTX_FETCH:
1204 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1205 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1207 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1209 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1210 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1211 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1212 case MONO_PATCH_INFO_GC_NURSERY_START:
1213 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1214 case MONO_PATCH_INFO_GOT_OFFSET:
1215 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1216 case MONO_PATCH_INFO_AOT_MODULE:
1217 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1218 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
1219 return (ji->type << 8);
1220 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1221 return (ji->type << 8) | (ji->data.index);
1222 case MONO_PATCH_INFO_SWITCH:
1223 return (ji->type << 8) | ji->data.table->table_size;
1224 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1225 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1226 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1227 /* Hash on the selector name */
1228 return g_str_hash (ji->data.target);
1229 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1230 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1231 case MONO_PATCH_INFO_LDSTR_LIT:
1232 return g_str_hash (ji->data.target);
1233 case MONO_PATCH_INFO_VIRT_METHOD: {
1234 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1236 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1238 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1239 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1240 return (ji->type << 8) | g_str_hash (ji->data.target);
1241 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1242 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1243 default:
1244 printf ("info type: %d\n", ji->type);
1245 mono_print_ji (ji); printf ("\n");
1246 g_assert_not_reached ();
1247 return 0;
1252 * mono_patch_info_equal:
1254 * This might fail to recognize equivalent patches, i.e. floats, so its only
1255 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1256 * in AOT.
1258 gint
1259 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1261 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1262 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1264 if (ji1->type != ji2->type)
1265 return 0;
1267 switch (ji1->type) {
1268 case MONO_PATCH_INFO_RVA:
1269 case MONO_PATCH_INFO_LDSTR:
1270 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1271 case MONO_PATCH_INFO_LDTOKEN:
1272 case MONO_PATCH_INFO_DECLSEC:
1273 if ((ji1->data.token->image != ji2->data.token->image) ||
1274 (ji1->data.token->token != ji2->data.token->token) ||
1275 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1276 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1277 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1278 return 0;
1279 break;
1280 case MONO_PATCH_INFO_INTERNAL_METHOD:
1281 return g_str_equal (ji1->data.name, ji2->data.name);
1282 case MONO_PATCH_INFO_RGCTX_FETCH:
1283 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1284 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1285 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1287 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);
1289 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1290 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1291 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1293 return c1->sig == c2->sig && c1->method == c2->method;
1295 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1296 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1297 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1298 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;
1299 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1300 return ji1->data.index == ji2->data.index;
1301 case MONO_PATCH_INFO_VIRT_METHOD:
1302 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1303 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1304 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
1305 if (ji1->data.target == ji2->data.target)
1306 return 1;
1307 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1308 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1309 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1310 default:
1311 if (ji1->data.target != ji2->data.target)
1312 return 0;
1313 break;
1316 return 1;
1319 gpointer
1320 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1322 unsigned char *ip = patch_info->ip.i + code;
1323 gconstpointer target = NULL;
1325 error_init (error);
1327 switch (patch_info->type) {
1328 case MONO_PATCH_INFO_BB:
1330 * FIXME: This could be hit for methods without a prolog. Should use -1
1331 * but too much code depends on a 0 initial value.
1333 //g_assert (patch_info->data.bb->native_offset);
1334 target = patch_info->data.bb->native_offset + code;
1335 break;
1336 case MONO_PATCH_INFO_ABS:
1337 target = patch_info->data.target;
1338 break;
1339 case MONO_PATCH_INFO_LABEL:
1340 target = patch_info->data.inst->inst_c0 + code;
1341 break;
1342 case MONO_PATCH_INFO_IP:
1343 target = ip;
1344 break;
1345 case MONO_PATCH_INFO_METHOD_REL:
1346 target = code + patch_info->data.offset;
1347 break;
1348 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1349 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1350 if (!mi) {
1351 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1352 g_assert_not_reached ();
1354 target = mono_icall_get_wrapper (mi);
1355 break;
1357 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1358 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
1359 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1360 if (!mi) {
1361 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1362 g_assert_not_reached ();
1364 target = mi->func;
1365 break;
1367 case MONO_PATCH_INFO_METHOD_JUMP:
1368 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1369 if (!mono_error_ok (error))
1370 return NULL;
1371 break;
1372 case MONO_PATCH_INFO_METHOD:
1373 if (patch_info->data.method == method) {
1374 target = code;
1375 } else {
1376 /* get the trampoline to the method from the domain */
1377 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1378 if (!mono_error_ok (error))
1379 return NULL;
1381 break;
1382 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1383 gpointer code_slot;
1385 mono_domain_lock (domain);
1386 if (!domain_jit_info (domain)->method_code_hash)
1387 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1388 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1389 if (!code_slot) {
1390 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1391 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1393 mono_domain_unlock (domain);
1394 target = code_slot;
1395 break;
1397 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1398 g_assert (mono_threads_are_safepoints_enabled ());
1399 target = (gpointer)&mono_polling_required;
1400 break;
1401 case MONO_PATCH_INFO_SWITCH: {
1402 gpointer *jump_table;
1403 int i;
1404 if (method && method->dynamic) {
1405 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1406 } else {
1407 if (mono_aot_only) {
1408 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1409 } else {
1410 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1414 for (i = 0; i < patch_info->data.table->table_size; i++) {
1415 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1418 target = jump_table;
1419 break;
1421 case MONO_PATCH_INFO_METHODCONST:
1422 case MONO_PATCH_INFO_CLASS:
1423 case MONO_PATCH_INFO_IMAGE:
1424 case MONO_PATCH_INFO_FIELD:
1425 case MONO_PATCH_INFO_SIGNATURE:
1426 case MONO_PATCH_INFO_AOT_MODULE:
1427 target = patch_info->data.target;
1428 break;
1429 case MONO_PATCH_INFO_IID:
1430 mono_class_init (patch_info->data.klass);
1431 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1432 break;
1433 case MONO_PATCH_INFO_ADJUSTED_IID:
1434 mono_class_init (patch_info->data.klass);
1435 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1436 break;
1437 case MONO_PATCH_INFO_VTABLE:
1438 target = mono_class_vtable_checked (domain, patch_info->data.klass, error);
1439 mono_error_assert_ok (error);
1440 break;
1441 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1442 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1444 if (del_tramp->is_virtual)
1445 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1446 else
1447 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1448 break;
1450 case MONO_PATCH_INFO_SFLDA: {
1451 MonoVTable *vtable = mono_class_vtable_checked (domain, patch_info->data.field->parent, error);
1452 mono_error_assert_ok (error);
1454 if (mono_class_field_is_special_static (patch_info->data.field)) {
1455 gpointer addr = NULL;
1457 mono_domain_lock (domain);
1458 if (domain->special_static_fields)
1459 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1460 mono_domain_unlock (domain);
1461 g_assert (addr);
1462 return addr;
1465 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1466 /* Done by the generated code */
1468 else {
1469 if (run_cctors) {
1470 if (!mono_runtime_class_init_full (vtable, error)) {
1471 return NULL;
1475 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1476 break;
1478 case MONO_PATCH_INFO_RVA: {
1479 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1480 guint32 rva;
1482 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1483 target = mono_image_rva_map (patch_info->data.token->image, rva);
1484 break;
1486 case MONO_PATCH_INFO_R4:
1487 case MONO_PATCH_INFO_R8:
1488 target = patch_info->data.target;
1489 break;
1490 case MONO_PATCH_INFO_EXC_NAME:
1491 target = patch_info->data.name;
1492 break;
1493 case MONO_PATCH_INFO_LDSTR:
1494 target =
1495 mono_ldstr_checked (domain, patch_info->data.token->image,
1496 mono_metadata_token_index (patch_info->data.token->token), error);
1497 break;
1498 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1499 gpointer handle;
1500 MonoClass *handle_class;
1502 handle = mono_ldtoken_checked (patch_info->data.token->image,
1503 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1504 if (!mono_error_ok (error))
1505 return NULL;
1506 mono_class_init (handle_class);
1507 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1509 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1510 if (!mono_error_ok (error))
1511 return NULL;
1512 break;
1514 case MONO_PATCH_INFO_LDTOKEN: {
1515 gpointer handle;
1516 MonoClass *handle_class;
1518 handle = mono_ldtoken_checked (patch_info->data.token->image,
1519 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1520 mono_error_assert_msg_ok (error, "Could not patch ldtoken");
1521 mono_class_init (handle_class);
1523 target = handle;
1524 break;
1526 case MONO_PATCH_INFO_DECLSEC:
1527 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1528 break;
1529 case MONO_PATCH_INFO_ICALL_ADDR:
1530 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1531 /* run_cctors == 0 -> AOT */
1532 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1533 const char *exc_class;
1534 const char *exc_arg;
1536 if (run_cctors) {
1537 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1538 if (!target) {
1539 if (mono_aot_only) {
1540 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1541 return NULL;
1543 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));
1545 } else {
1546 target = NULL;
1548 } else {
1549 target = mono_lookup_internal_call (patch_info->data.method);
1551 if (!target && run_cctors)
1552 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1554 break;
1555 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1556 target = mono_thread_interruption_request_flag ();
1557 break;
1558 case MONO_PATCH_INFO_METHOD_RGCTX:
1559 target = mini_method_get_rgctx (patch_info->data.method);
1560 break;
1561 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1562 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1564 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1565 break;
1567 case MONO_PATCH_INFO_BB_OVF:
1568 case MONO_PATCH_INFO_EXC_OVF:
1569 case MONO_PATCH_INFO_GOT_OFFSET:
1570 case MONO_PATCH_INFO_NONE:
1571 break;
1572 case MONO_PATCH_INFO_RGCTX_FETCH: {
1573 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1575 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1576 break;
1578 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1579 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1580 if (!run_cctors)
1581 /* AOT, not needed */
1582 target = NULL;
1583 else
1584 target = mono_arch_get_seq_point_info (domain, code);
1585 break;
1586 #endif
1587 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1588 int card_table_shift_bits;
1589 gpointer card_table_mask;
1591 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1592 break;
1594 case MONO_PATCH_INFO_GC_NURSERY_START: {
1595 int shift_bits;
1596 size_t size;
1598 target = mono_gc_get_nursery (&shift_bits, &size);
1599 break;
1601 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1602 int shift_bits;
1603 size_t size;
1605 mono_gc_get_nursery (&shift_bits, &size);
1607 target = (gpointer)(mgreg_t)shift_bits;
1608 break;
1610 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1611 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1612 break;
1614 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1615 target = NULL;
1616 break;
1618 case MONO_PATCH_INFO_LDSTR_LIT: {
1619 int len;
1620 char *s;
1622 len = strlen ((const char *)patch_info->data.target);
1623 s = (char *)mono_domain_alloc0 (domain, len + 1);
1624 memcpy (s, patch_info->data.target, len);
1625 target = s;
1627 break;
1629 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1630 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1631 break;
1632 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1633 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1634 break;
1635 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1636 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1637 break;
1638 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1639 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1640 g_assert (mi);
1641 target = mi->func;
1642 break;
1644 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
1645 target = (gpointer) &mono_profiler_state.gc_allocation_count;
1646 break;
1648 default:
1649 g_assert_not_reached ();
1652 return (gpointer)target;
1656 * mini_register_jump_site:
1658 * Register IP as a jump/tail call site which calls METHOD.
1659 * This is needed because common_call_trampoline () cannot patch
1660 * the call site because the caller ip is not available for jumps.
1662 void
1663 mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip)
1665 ERROR_DECL (error);
1666 MonoJumpList *jlist;
1668 if (mono_method_is_generic_sharable (method, TRUE)) {
1669 method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1670 mono_error_assert_ok (error);
1673 mono_domain_lock (domain);
1674 jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, method);
1675 if (!jlist) {
1676 jlist = (MonoJumpList *)mono_domain_alloc0 (domain, sizeof (MonoJumpList));
1677 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, method, jlist);
1679 jlist->list = g_slist_prepend (jlist->list, ip);
1680 mono_domain_unlock (domain);
1684 * mini_patch_jump_sites:
1686 * Patch jump/tail call sites calling METHOD so the jump to ADDR.
1688 void
1689 mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr)
1691 ERROR_DECL (error);
1692 GHashTable *hash = domain_jit_info (domain)->jump_target_hash;
1694 if (!hash)
1695 return;
1697 MonoJumpInfo patch_info;
1698 MonoJumpList *jlist;
1699 GSList *tmp;
1701 /* The caller/callee might use different instantiations */
1702 if (mono_method_is_generic_sharable (method, TRUE)) {
1703 method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
1704 mono_error_assert_ok (error);
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 (method->klass->image, 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;
1912 static JitCompilationData compilation_data;
1913 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1915 static void
1916 mini_jit_init_job_control (void)
1918 mono_coop_mutex_init (&compilation_data.lock);
1919 compilation_data.in_flight_methods = g_ptr_array_new ();
1922 static void
1923 lock_compilation_data (void)
1925 mono_coop_mutex_lock (&compilation_data.lock);
1928 static void
1929 unlock_compilation_data (void)
1931 mono_coop_mutex_unlock (&compilation_data.lock);
1934 static JitCompilationEntry*
1935 find_method (MonoMethod *method, MonoDomain *domain)
1937 int i;
1938 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1939 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1940 if (e->method == method && e->domain == domain)
1941 return e;
1944 return NULL;
1947 static void
1948 add_current_thread (MonoJitTlsData *jit_tls)
1950 ++jit_tls->active_jit_methods;
1953 static void
1954 unref_jit_entry (JitCompilationEntry *entry)
1956 --entry->ref_count;
1957 if (entry->ref_count)
1958 return;
1959 if (entry->has_cond)
1960 mono_coop_cond_destroy (&entry->cond);
1961 g_free (entry);
1965 * Returns true if this method waited successfully for another thread to JIT it
1967 static gboolean
1968 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1970 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1971 JitCompilationEntry *entry;
1973 static gboolean inited;
1974 if (!inited) {
1975 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1976 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1977 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1978 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1979 inited = TRUE;
1982 lock_compilation_data ();
1984 if (!(entry = find_method (method, domain))) {
1985 entry = g_new0 (JitCompilationEntry, 1);
1986 entry->method = method;
1987 entry->domain = domain;
1988 entry->compilation_count = entry->ref_count = 1;
1989 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1990 g_assert (find_method (method, domain) == entry);
1991 add_current_thread (jit_tls);
1993 unlock_compilation_data ();
1994 return FALSE;
1995 } else if (jit_tls->active_jit_methods > 0) {
1996 //We can't suspend the current thread if it's already JITing a method.
1997 //Dependency management is too compilated and we want to get rid of this anyways.
1998 ++entry->compilation_count;
1999 ++jit_methods_multiple;
2000 ++jit_tls->active_jit_methods;
2002 unlock_compilation_data ();
2003 return FALSE;
2004 } else {
2005 ++jit_methods_waited;
2006 ++entry->ref_count;
2008 if (!entry->has_cond) {
2009 mono_coop_cond_init (&entry->cond);
2010 entry->has_cond = TRUE;
2013 while (TRUE) {
2014 ++entry->threads_waiting;
2016 g_assert (entry->has_cond);
2017 mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
2018 --entry->threads_waiting;
2020 if (entry->done) {
2021 unref_jit_entry (entry);
2022 unlock_compilation_data ();
2023 return TRUE;
2024 } else {
2025 ++jit_spurious_wakeups;
2031 static void
2032 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
2034 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2036 lock_compilation_data ();
2038 g_assert (jit_tls->active_jit_methods > 0);
2039 --jit_tls->active_jit_methods;
2041 JitCompilationEntry *entry = find_method (method, target_domain);
2042 g_assert (entry); // It would be weird to fail
2043 entry->done = TRUE;
2045 if (entry->threads_waiting) {
2046 g_assert (entry->has_cond);
2047 mono_coop_cond_broadcast (&entry->cond);
2050 if (--entry->compilation_count == 0) {
2051 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
2052 unref_jit_entry (entry);
2055 unlock_compilation_data ();
2059 static gpointer
2060 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
2062 MonoDomain *target_domain, *domain = mono_domain_get ();
2063 MonoJitInfo *info;
2064 gpointer code = NULL, p;
2065 MonoJitInfo *ji;
2066 MonoJitICallInfo *callinfo = NULL;
2067 WrapperInfo *winfo = NULL;
2069 error_init (error);
2071 if (mono_use_interpreter && !jit_only) {
2072 code = mini_get_interp_callbacks ()->create_method_pointer (method, error);
2073 if (code)
2074 return code;
2077 if (mono_llvm_only)
2078 /* Should be handled by the caller */
2079 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
2082 * ICALL wrappers are handled specially, since there is only one copy of them
2083 * shared by all appdomains.
2085 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2086 winfo = mono_marshal_get_wrapper_info (method);
2087 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
2088 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
2089 g_assert (callinfo);
2091 /* Must be domain neutral since there is only one copy */
2092 opt |= MONO_OPT_SHARED;
2093 } else {
2094 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
2095 opt &= ~MONO_OPT_SHARED;
2098 if (opt & MONO_OPT_SHARED)
2099 target_domain = mono_get_root_domain ();
2100 else
2101 target_domain = domain;
2103 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2104 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2106 g_assert (info);
2107 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
2108 MonoGenericContext *ctx = NULL;
2109 if (method->is_inflated)
2110 ctx = mono_method_get_context (method);
2111 method = info->d.synchronized_inner.method;
2112 if (ctx) {
2113 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2114 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2119 lookup_start:
2120 info = lookup_method (target_domain, method);
2121 if (info) {
2122 /* We can't use a domain specific method in another domain */
2123 if (! ((domain != target_domain) && !info->domain_neutral)) {
2124 MonoVTable *vtable;
2126 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2127 vtable = mono_class_vtable_checked (domain, method->klass, error);
2128 if (!is_ok (error))
2129 return NULL;
2130 g_assert (vtable);
2131 if (!mono_runtime_class_init_full (vtable, error))
2132 return NULL;
2133 return mono_create_ftnptr (target_domain, info->code_start);
2137 #ifdef MONO_USE_AOT_COMPILER
2138 if (opt & MONO_OPT_AOT) {
2139 MonoDomain *domain = NULL;
2141 if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2142 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2143 g_assert (info);
2144 if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
2145 /* AOT'd wrappers for interp must be owned by root domain */
2146 domain = mono_get_root_domain ();
2149 if (!domain)
2150 domain = mono_domain_get ();
2152 mono_class_init (method->klass);
2154 if ((code = mono_aot_get_method (domain, method, error))) {
2155 MonoVTable *vtable;
2157 if (mono_gc_is_critical_method (method)) {
2159 * The suspend code needs to be able to lookup these methods by ip in async context,
2160 * so preload their jit info.
2162 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2163 g_assert (ji);
2167 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2168 * This is not a problem, since it will be initialized when the method is first
2169 * called by init_method ().
2171 if (!mono_llvm_only && !mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
2172 vtable = mono_class_vtable_checked (domain, method->klass, error);
2173 mono_error_assert_ok (error);
2174 if (!mono_runtime_class_init_full (vtable, error))
2175 return NULL;
2178 if (!is_ok (error))
2179 return NULL;
2181 #endif
2183 if (!code && mono_llvm_only) {
2184 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2185 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2187 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2189 * These wrappers are only created for signatures which are in the program, but
2190 * sometimes we load methods too eagerly and have to create them even if they
2191 * will never be called.
2193 return no_gsharedvt_in_wrapper;
2198 if (!code) {
2199 if (mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
2200 mono_error_set_invalid_operation (error, "Could not execute the method because the containing type is not fully instantiated.");
2201 return NULL;
2203 if (wait_or_register_method_to_compile (method, target_domain))
2204 goto lookup_start;
2205 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2206 unregister_method_for_compile (method, target_domain);
2208 if (!mono_error_ok (error))
2209 return NULL;
2211 if (!code && mono_llvm_only) {
2212 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2213 g_assert_not_reached ();
2216 if (!code)
2217 return NULL;
2219 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2220 MonoDomain *d;
2223 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2225 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2226 g_assert (ji);
2229 p = mono_create_ftnptr (target_domain, code);
2231 if (callinfo) {
2232 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2233 mono_loader_lock ();
2234 mono_jit_lock ();
2235 if (!callinfo->wrapper) {
2236 callinfo->wrapper = p;
2237 mono_register_jit_icall_wrapper (callinfo, p);
2239 mono_jit_unlock ();
2240 mono_loader_unlock ();
2243 return p;
2246 gpointer
2247 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2249 gpointer code;
2251 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2252 return code;
2256 * mono_jit_compile_method_jit_only:
2258 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2260 gpointer
2261 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2263 gpointer code;
2265 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2266 return code;
2269 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2270 static void
2271 invalidated_delegate_trampoline (char *desc)
2273 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2274 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2275 desc);
2277 #endif
2280 * mono_jit_free_method:
2282 * Free all memory allocated by the JIT for METHOD.
2284 static void
2285 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2287 MonoJitDynamicMethodInfo *ji;
2288 gboolean destroy = TRUE;
2289 GHashTableIter iter;
2290 MonoJumpList *jlist;
2291 MonoJitDomainInfo *info = domain_jit_info (domain);
2293 g_assert (method->dynamic);
2295 if (mono_use_interpreter) {
2296 mono_domain_jit_code_hash_lock (domain);
2297 /* InterpMethod is allocated in the domain mempool */
2298 mono_internal_hash_table_remove (&info->interp_code_hash, method);
2299 mono_domain_jit_code_hash_unlock (domain);
2302 mono_domain_lock (domain);
2303 ji = mono_dynamic_code_hash_lookup (domain, method);
2304 mono_domain_unlock (domain);
2306 if (!ji)
2307 return;
2309 mono_debug_remove_method (method, domain);
2310 mono_lldb_remove_method (domain, method, ji);
2312 mono_domain_lock (domain);
2313 g_hash_table_remove (info->dynamic_code_hash, method);
2314 mono_domain_jit_code_hash_lock (domain);
2315 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2316 mono_domain_jit_code_hash_unlock (domain);
2317 g_hash_table_remove (info->jump_trampoline_hash, method);
2318 g_hash_table_remove (info->seq_points, method);
2320 /* requires the domain lock - took above */
2321 mono_conc_hashtable_remove (info->runtime_invoke_hash, method);
2323 /* Remove jump targets in this method */
2324 g_hash_table_iter_init (&iter, info->jump_target_hash);
2325 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2326 GSList *tmp, *remove;
2328 remove = NULL;
2329 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2330 guint8 *ip = (guint8 *)tmp->data;
2332 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2333 remove = g_slist_prepend (remove, tmp);
2335 for (tmp = remove; tmp; tmp = tmp->next) {
2336 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2338 g_slist_free (remove);
2340 mono_domain_unlock (domain);
2342 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2343 if (mini_debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2345 * Instead of freeing the code, change it to call an error routine
2346 * so people can fix their code.
2348 char *type = mono_type_full_name (&method->klass->byval_arg);
2349 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2351 g_free (type);
2352 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2353 destroy = FALSE;
2355 #endif
2358 * This needs to be done before freeing code_mp, since the code address is the
2359 * key in the table, so if we free the code_mp first, another thread can grab the
2360 * same code address and replace our entry in the table.
2362 mono_jit_info_table_remove (domain, ji->ji);
2364 if (destroy)
2365 mono_code_manager_destroy (ji->code_mp);
2366 g_free (ji);
2369 gpointer
2370 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2372 MonoDomain *target_domain;
2373 MonoJitInfo *info;
2375 if (default_opt & MONO_OPT_SHARED)
2376 target_domain = mono_get_root_domain ();
2377 else
2378 target_domain = domain;
2380 info = lookup_method (target_domain, method);
2381 if (info) {
2382 /* We can't use a domain specific method in another domain */
2383 if (! ((domain != target_domain) && !info->domain_neutral)) {
2384 mono_atomic_inc_i32 (&mono_jit_stats.methods_lookups);
2385 if (ji)
2386 *ji = info;
2387 return info->code_start;
2391 if (ji)
2392 *ji = NULL;
2393 return NULL;
2396 static guint32 bisect_opt = 0;
2397 static GHashTable *bisect_methods_hash = NULL;
2399 void
2400 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2402 FILE *file;
2403 char method_name [2048];
2405 bisect_opt = opt;
2406 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2407 g_assert (bisect_methods_hash);
2409 file = fopen (method_list_filename, "r");
2410 g_assert (file);
2412 while (fgets (method_name, sizeof (method_name), file)) {
2413 size_t len = strlen (method_name);
2414 g_assert (len > 0);
2415 g_assert (method_name [len - 1] == '\n');
2416 method_name [len - 1] = 0;
2417 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2419 g_assert (feof (file));
2422 gboolean mono_do_single_method_regression = FALSE;
2423 guint32 mono_single_method_regression_opt = 0;
2424 MonoMethod *mono_current_single_method;
2425 GSList *mono_single_method_list;
2426 GHashTable *mono_single_method_hash;
2428 guint32
2429 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2431 g_assert (method);
2433 if (bisect_methods_hash) {
2434 char *name = mono_method_full_name (method, TRUE);
2435 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2436 g_free (name);
2437 if (res)
2438 return default_opt | bisect_opt;
2440 if (!mono_do_single_method_regression)
2441 return default_opt;
2442 if (!mono_current_single_method) {
2443 if (!mono_single_method_hash)
2444 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2445 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2446 g_hash_table_insert (mono_single_method_hash, method, method);
2447 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2449 return default_opt;
2451 if (method == mono_current_single_method)
2452 return mono_single_method_regression_opt;
2453 return default_opt;
2456 gpointer
2457 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2459 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2462 typedef struct {
2463 MonoMethod *method;
2464 gpointer compiled_method;
2465 gpointer runtime_invoke;
2466 MonoVTable *vtable;
2467 MonoDynCallInfo *dyn_call_info;
2468 MonoClass *ret_box_class;
2469 MonoMethodSignature *sig;
2470 gboolean gsharedvt_invoke;
2471 gpointer *wrapper_arg;
2472 } RuntimeInvokeInfo;
2474 static RuntimeInvokeInfo*
2475 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2477 MonoMethod *invoke;
2478 RuntimeInvokeInfo *info;
2480 info = g_new0 (RuntimeInvokeInfo, 1);
2481 info->compiled_method = compiled_method;
2482 if (mono_llvm_only && method->string_ctor)
2483 info->sig = mono_marshal_get_string_ctor_signature (method);
2484 else
2485 info->sig = mono_method_signature (method);
2487 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2488 info->vtable = mono_class_vtable_checked (domain, method->klass, error);
2489 if (!mono_error_ok (error))
2490 return NULL;
2491 g_assert (info->vtable);
2493 MonoMethodSignature *sig = info->sig;
2494 MonoType *ret_type;
2497 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2498 * in full-aot mode, so we use a slower, but more generic wrapper if
2499 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2501 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2502 if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) {
2503 gboolean supported = TRUE;
2504 int i;
2506 if (method->string_ctor)
2507 sig = mono_marshal_get_string_ctor_signature (method);
2509 for (i = 0; i < sig->param_count; ++i) {
2510 MonoType *t = sig->params [i];
2512 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2513 supported = FALSE;
2516 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2517 supported = FALSE;
2519 if (supported) {
2520 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2521 if (mini_debug_options.dyn_runtime_invoke)
2522 g_assert (info->dyn_call_info);
2525 #endif
2527 ret_type = sig->ret;
2528 switch (ret_type->type) {
2529 case MONO_TYPE_VOID:
2530 break;
2531 case MONO_TYPE_I1:
2532 case MONO_TYPE_U1:
2533 case MONO_TYPE_I2:
2534 case MONO_TYPE_U2:
2535 case MONO_TYPE_I4:
2536 case MONO_TYPE_U4:
2537 case MONO_TYPE_I:
2538 case MONO_TYPE_U:
2539 case MONO_TYPE_I8:
2540 case MONO_TYPE_U8:
2541 case MONO_TYPE_BOOLEAN:
2542 case MONO_TYPE_CHAR:
2543 case MONO_TYPE_R4:
2544 case MONO_TYPE_R8:
2545 info->ret_box_class = mono_class_from_mono_type (ret_type);
2546 break;
2547 case MONO_TYPE_PTR:
2548 info->ret_box_class = mono_defaults.int_class;
2549 break;
2550 case MONO_TYPE_STRING:
2551 case MONO_TYPE_CLASS:
2552 case MONO_TYPE_ARRAY:
2553 case MONO_TYPE_SZARRAY:
2554 case MONO_TYPE_OBJECT:
2555 break;
2556 case MONO_TYPE_GENERICINST:
2557 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2558 info->ret_box_class = mono_class_from_mono_type (ret_type);
2559 break;
2560 case MONO_TYPE_VALUETYPE:
2561 info->ret_box_class = mono_class_from_mono_type (ret_type);
2562 break;
2563 default:
2564 g_assert_not_reached ();
2565 break;
2568 if (!info->dyn_call_info) {
2569 if (mono_llvm_only) {
2570 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2571 g_assert_not_reached ();
2572 #endif
2573 info->gsharedvt_invoke = TRUE;
2574 if (!callee_gsharedvt) {
2575 /* Invoke a gsharedvt out wrapper instead */
2576 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2577 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2579 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2580 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2582 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2583 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2584 g_free (wrapper_sig);
2586 info->compiled_method = mono_jit_compile_method (wrapper, error);
2587 if (!mono_error_ok (error)) {
2588 g_free (info);
2589 return NULL;
2591 } else {
2592 /* Gsharedvt methods can be invoked the same way */
2593 /* The out wrapper has the same signature as the compiled gsharedvt method */
2594 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2596 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2598 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2599 g_free (wrapper_sig);
2602 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2603 if (!mono_error_ok (error)) {
2604 g_free (info);
2605 return NULL;
2609 return info;
2612 static MonoObject*
2613 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2615 MonoMethodSignature *sig = info->sig;
2616 MonoDomain *domain = mono_domain_get ();
2617 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2618 gpointer *args;
2619 gpointer retval_ptr;
2620 guint8 retval [256];
2621 gpointer *param_refs;
2622 int i, pindex;
2624 error_init (error);
2626 g_assert (info->gsharedvt_invoke);
2629 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2630 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2631 * signatures, so we only have to generate runtime invoke wrappers for these
2632 * signatures.
2633 * This code also handles invocation of gsharedvt methods directly, no
2634 * out wrappers are used in that case.
2636 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2637 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2638 pindex = 0;
2640 * The runtime invoke wrappers expects pointers to primitive types, so have to
2641 * use indirections.
2643 if (sig->hasthis)
2644 args [pindex ++] = &obj;
2645 if (sig->ret->type != MONO_TYPE_VOID) {
2646 retval_ptr = (gpointer)&retval;
2647 args [pindex ++] = &retval_ptr;
2649 for (i = 0; i < sig->param_count; ++i) {
2650 MonoType *t = sig->params [i];
2652 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2653 MonoClass *klass = mono_class_from_mono_type (t);
2654 guint8 *nullable_buf;
2655 int size;
2657 size = mono_class_value_size (klass, NULL);
2658 nullable_buf = g_alloca (size);
2659 g_assert (nullable_buf);
2661 /* The argument pointed to by params [i] is either a boxed vtype or null */
2662 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2663 params [i] = nullable_buf;
2666 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2667 param_refs [i] = params [i];
2668 params [i] = &(param_refs [i]);
2670 args [pindex ++] = &params [i];
2672 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2673 args [pindex ++] = &info->wrapper_arg;
2675 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2677 runtime_invoke (NULL, args, exc, info->compiled_method);
2678 if (exc && *exc)
2679 return NULL;
2681 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2682 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2683 else
2684 return *(MonoObject**)retval;
2688 * mono_jit_runtime_invoke:
2689 * \param method: the method to invoke
2690 * \param obj: this pointer
2691 * \param params: array of parameter values.
2692 * \param exc: Set to the exception raised in the managed method.
2693 * \param error: error or caught exception object
2694 * If \p exc is NULL, \p error is thrown instead.
2695 * If coop is enabled, \p exc argument is ignored -
2696 * all exceptions are caught and propagated through \p error
2698 static MonoObject*
2699 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2701 MonoMethod *invoke, *callee;
2702 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2703 MonoDomain *domain = mono_domain_get ();
2704 MonoJitDomainInfo *domain_info;
2705 RuntimeInvokeInfo *info, *info2;
2706 MonoJitInfo *ji = NULL;
2707 gboolean callee_gsharedvt = FALSE;
2709 if (mono_use_interpreter)
2710 return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error);
2712 error_init (error);
2713 if (exc)
2714 *exc = NULL;
2716 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2717 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2718 return NULL;
2721 domain_info = domain_jit_info (domain);
2723 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2725 if (!info) {
2726 if (mono_security_core_clr_enabled ()) {
2728 * This might be redundant since mono_class_vtable () already does this,
2729 * but keep it just in case for moonlight.
2731 mono_class_setup_vtable (method->klass);
2732 if (mono_class_has_failure (method->klass)) {
2733 mono_error_set_for_class_failure (error, method->klass);
2734 if (exc)
2735 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2736 return NULL;
2740 gpointer compiled_method;
2742 callee = method;
2743 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2744 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2746 * Array Get/Set/Address methods. The JIT implements them using inline code
2747 * inside the runtime invoke wrappers, so no need to compile them.
2749 if (mono_aot_only) {
2751 * Call a wrapper, since the runtime invoke wrapper was not generated.
2753 MonoMethod *wrapper;
2755 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2756 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2757 callee = wrapper;
2758 } else {
2759 callee = NULL;
2763 if (callee) {
2764 compiled_method = mono_jit_compile_method (callee, error);
2765 if (!compiled_method) {
2766 g_assert (!mono_error_ok (error));
2767 return NULL;
2770 if (mono_llvm_only) {
2771 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2772 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2773 if (callee_gsharedvt)
2774 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2777 if (!callee_gsharedvt)
2778 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2779 } else {
2780 compiled_method = NULL;
2783 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2784 if (!mono_error_ok (error))
2785 return NULL;
2787 mono_domain_lock (domain);
2788 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2789 mono_domain_unlock (domain);
2790 if (info2) {
2791 g_free (info);
2792 info = info2;
2797 * We need this here because mono_marshal_get_runtime_invoke can place
2798 * the helper method in System.Object and not the target class.
2800 if (!mono_runtime_class_init_full (info->vtable, error)) {
2801 if (exc)
2802 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2803 return NULL;
2806 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2807 we always catch the exception and propagate it through the MonoError */
2808 gboolean catchExcInMonoError =
2809 (exc == NULL) && mono_threads_are_safepoints_enabled ();
2810 MonoObject *invoke_exc = NULL;
2811 if (catchExcInMonoError)
2812 exc = &invoke_exc;
2814 /* The wrappers expect this to be initialized to NULL */
2815 if (exc)
2816 *exc = NULL;
2818 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2819 if (info->dyn_call_info) {
2820 MonoMethodSignature *sig = mono_method_signature (method);
2821 gpointer *args;
2822 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2823 int i, pindex, buf_size;
2824 guint8 *buf;
2825 guint8 retval [256];
2827 if (!dyn_runtime_invoke) {
2828 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2829 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2830 if (!mono_error_ok (error))
2831 return NULL;
2834 /* Convert the arguments to the format expected by start_dyn_call () */
2835 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2836 pindex = 0;
2837 if (sig->hasthis)
2838 args [pindex ++] = &obj;
2839 for (i = 0; i < sig->param_count; ++i) {
2840 MonoType *t = sig->params [i];
2842 if (t->byref) {
2843 args [pindex ++] = &params [i];
2844 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2845 args [pindex ++] = &params [i];
2846 } else {
2847 args [pindex ++] = params [i];
2851 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2853 buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
2854 buf = g_alloca (buf_size);
2855 g_assert (buf);
2857 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
2859 dyn_runtime_invoke (buf, exc, info->compiled_method);
2860 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2862 if (catchExcInMonoError && *exc != NULL) {
2863 mono_error_set_exception_instance (error, (MonoException*) *exc);
2864 return NULL;
2867 if (info->ret_box_class)
2868 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2869 else
2870 return *(MonoObject**)retval;
2872 #endif
2874 MonoObject *result;
2876 if (mono_llvm_only) {
2877 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2878 if (!is_ok (error))
2879 return NULL;
2880 } else {
2881 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2883 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2885 if (catchExcInMonoError && *exc != NULL)
2886 mono_error_set_exception_instance (error, (MonoException*) *exc);
2887 return result;
2890 typedef struct {
2891 MonoVTable *vtable;
2892 int slot;
2893 } IMTTrampInfo;
2895 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2898 * mini_llvmonly_initial_imt_tramp:
2900 * This function is called the first time a call is made through an IMT trampoline.
2901 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2903 static gpointer
2904 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2906 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2907 gpointer *imt;
2908 gpointer *ftndesc;
2909 IMTTrampFunc func;
2911 mono_vtable_build_imt_slot (info->vtable, info->slot);
2913 imt = (gpointer*)info->vtable;
2914 imt -= MONO_IMT_SIZE;
2916 /* Return what the real IMT trampoline returns */
2917 ftndesc = imt [info->slot];
2918 func = ftndesc [0];
2920 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2921 /* Happens when the imt slot contains only a generic virtual method */
2922 return NULL;
2923 return func ((gpointer *)ftndesc [1], imt_method);
2926 /* This is called indirectly through an imt slot. */
2927 static gpointer
2928 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2930 int i = 0;
2932 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2933 while (arg [i] && arg [i] != imt_method)
2934 i += 2;
2935 g_assert (arg [i]);
2937 return arg [i + 1];
2940 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2941 static gpointer
2942 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2944 //g_assert (arg [0] == imt_method);
2945 return arg [1];
2948 static gpointer
2949 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2951 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2952 if (arg [0] == imt_method)
2953 return arg [1];
2954 else
2955 return arg [3];
2958 static gpointer
2959 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2961 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2962 if (arg [0] == imt_method)
2963 return arg [1];
2964 else if (arg [2] == imt_method)
2965 return arg [3];
2966 else
2967 return arg [5];
2971 * A version of the imt trampoline used for generic virtual/variant iface methods.
2972 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2973 * in the search table. The original JIT code had a 'fallback' trampoline it could
2974 * call, but we can't do that, so we just return NULL, and the compiled code
2975 * will handle it.
2977 static gpointer
2978 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2980 int i = 0;
2982 while (arg [i] && arg [i] != imt_method)
2983 i += 2;
2984 if (!arg [i])
2985 return NULL;
2987 return arg [i + 1];
2990 static gpointer
2991 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2993 gpointer *buf;
2994 gpointer *res;
2995 int i, index, real_count;
2996 gboolean virtual_generic = FALSE;
2999 * Create an array which is passed to the imt trampoline functions.
3000 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
3003 real_count = 0;
3004 for (i = 0; i < count; ++i) {
3005 MonoIMTCheckItem *item = imt_entries [i];
3007 if (item->is_equals)
3008 real_count ++;
3009 if (item->has_target_code)
3010 virtual_generic = TRUE;
3014 * Initialize all vtable entries reachable from this imt slot, so the compiled
3015 * code doesn't have to check it.
3017 for (i = 0; i < count; ++i) {
3018 MonoIMTCheckItem *item = imt_entries [i];
3019 int vt_slot;
3021 if (!item->is_equals || item->has_target_code)
3022 continue;
3023 vt_slot = item->value.vtable_slot;
3024 mono_init_vtable_slot (vtable, vt_slot);
3027 /* Save the entries into an array */
3028 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
3029 index = 0;
3030 for (i = 0; i < count; ++i) {
3031 MonoIMTCheckItem *item = imt_entries [i];
3033 if (!item->is_equals)
3034 continue;
3036 g_assert (item->key);
3037 buf [(index * 2)] = item->key;
3038 if (item->has_target_code)
3039 buf [(index * 2) + 1] = item->value.target_code;
3040 else
3041 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
3042 index ++;
3044 buf [(index * 2)] = NULL;
3045 buf [(index * 2) + 1] = fail_tramp;
3048 * Return a function descriptor for a C function with 'buf' as its argument.
3049 * It will by called by JITted code.
3051 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
3052 switch (real_count) {
3053 case 1:
3054 res [0] = mono_llvmonly_imt_tramp_1;
3055 break;
3056 case 2:
3057 res [0] = mono_llvmonly_imt_tramp_2;
3058 break;
3059 case 3:
3060 res [0] = mono_llvmonly_imt_tramp_3;
3061 break;
3062 default:
3063 res [0] = mono_llvmonly_imt_tramp;
3064 break;
3066 if (virtual_generic || fail_tramp)
3067 res [0] = mono_llvmonly_fallback_imt_tramp;
3068 res [1] = buf;
3070 return res;
3073 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
3075 MonoException *exc = NULL;
3076 MonoJitInfo *ji;
3077 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3078 MONO_SIG_HANDLER_GET_CONTEXT;
3080 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3082 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3084 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
3085 if (mono_arch_is_int_overflow (ctx, info))
3087 * The spec says this throws ArithmeticException, but MS throws the derived
3088 * OverflowException.
3090 exc = mono_get_exception_overflow ();
3091 else
3092 exc = mono_get_exception_divide_by_zero ();
3093 #else
3094 exc = mono_get_exception_divide_by_zero ();
3095 #endif
3097 if (!ji) {
3098 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3099 goto exit;
3101 mono_handle_native_crash ("SIGFPE", ctx, info);
3102 if (mono_do_crash_chaining) {
3103 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3104 goto exit;
3108 mono_arch_handle_exception (ctx, exc);
3110 exit:
3111 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3114 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
3116 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3117 MONO_SIG_HANDLER_GET_CONTEXT;
3119 if (mono_runtime_get_no_exec ())
3120 exit (1);
3123 mono_handle_native_crash ("SIGILL", ctx, info);
3124 if (mono_do_crash_chaining) {
3125 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3126 return;
3129 g_assert_not_reached ();
3132 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
3133 #define HAVE_SIG_INFO
3134 #endif
3136 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
3138 MonoJitInfo *ji;
3139 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3140 gpointer fault_addr = NULL;
3141 #ifdef HAVE_SIG_INFO
3142 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3143 #else
3144 void *info = NULL;
3145 #endif
3146 MONO_SIG_HANDLER_GET_CONTEXT;
3148 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3149 if (mono_arch_is_single_step_event (info, ctx)) {
3150 mono_debugger_agent_single_step_event (ctx);
3151 return;
3152 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3153 mono_debugger_agent_breakpoint_hit (ctx);
3154 return;
3156 #endif
3158 #if defined(HAVE_SIG_INFO)
3159 #if !defined(HOST_WIN32)
3160 fault_addr = info->si_addr;
3161 if (mono_aot_is_pagefault (info->si_addr)) {
3162 mono_aot_handle_pagefault (info->si_addr);
3163 return;
3165 #endif
3167 /* The thread might no be registered with the runtime */
3168 if (!mono_domain_get () || !jit_tls) {
3169 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3170 return;
3171 mono_handle_native_crash ("SIGSEGV", ctx, info);
3172 if (mono_do_crash_chaining) {
3173 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3174 return;
3177 #endif
3179 ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
3181 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3182 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3183 return;
3185 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3186 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3187 fault_addr = info->si_addr;
3188 if (fault_addr == NULL) {
3189 MonoContext mctx;
3191 mono_sigctx_to_monoctx (ctx, &mctx);
3193 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3195 #endif
3197 if (jit_tls->stack_size &&
3198 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3200 * The hard-guard page has been hit: there is not much we can do anymore
3201 * Print a hopefully clear message and abort.
3203 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3204 g_assert_not_reached ();
3205 } else {
3206 /* The original handler might not like that it is executed on an altstack... */
3207 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3208 return;
3210 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3212 #else
3214 if (!ji) {
3215 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3216 return;
3218 mono_handle_native_crash ("SIGSEGV", ctx, info);
3220 if (mono_do_crash_chaining) {
3221 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3222 return;
3226 mono_arch_handle_exception (ctx, NULL);
3227 #endif
3230 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3232 MonoException *exc;
3233 MONO_SIG_HANDLER_GET_CONTEXT;
3235 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3237 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3239 mono_arch_handle_exception (ctx, exc);
3241 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3244 #ifndef DISABLE_REMOTING
3245 /* mono_jit_create_remoting_trampoline:
3246 * @method: pointer to the method info
3248 * Creates a trampoline which calls the remoting functions. This
3249 * is used in the vtable of transparent proxies.
3251 * Returns: a pointer to the newly created code
3253 static gpointer
3254 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3256 MonoMethod *nm;
3257 guint8 *addr = NULL;
3259 error_init (error);
3261 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3262 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3263 domain, NULL);
3266 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3267 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3268 nm = mono_marshal_get_remoting_invoke_for_target (method, target, error);
3269 else
3270 nm = method;
3271 return_val_if_nok (error, NULL);
3272 addr = (guint8 *)mono_compile_method_checked (nm, error);
3273 return_val_if_nok (error, NULL);
3274 return mono_get_addr_from_ftnptr (addr);
3276 #endif
3278 static G_GNUC_UNUSED void
3279 no_imt_trampoline (void)
3281 g_assert_not_reached ();
3284 static G_GNUC_UNUSED void
3285 no_vcall_trampoline (void)
3287 g_assert_not_reached ();
3290 static gpointer *vtable_trampolines;
3291 static int vtable_trampolines_size;
3293 gpointer
3294 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3296 int index = slot_index + MONO_IMT_SIZE;
3298 if (mono_llvm_only) {
3299 if (slot_index < 0) {
3300 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3301 // FIXME: Memory management
3302 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3303 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3304 info->vtable = vt;
3305 info->slot = index;
3306 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3307 ftndesc [1] = info;
3308 mono_memory_barrier ();
3309 return ftndesc;
3310 } else {
3311 return NULL;
3315 g_assert (slot_index >= - MONO_IMT_SIZE);
3316 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3317 mono_jit_lock ();
3318 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3319 int new_size;
3320 gpointer new_table;
3322 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3323 while (new_size <= index)
3324 new_size *= 2;
3325 new_table = g_new0 (gpointer, new_size);
3327 if (vtable_trampolines)
3328 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3329 g_free (vtable_trampolines);
3330 mono_memory_barrier ();
3331 vtable_trampolines = (void **)new_table;
3332 vtable_trampolines_size = new_size;
3334 mono_jit_unlock ();
3337 if (!vtable_trampolines [index])
3338 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3339 return vtable_trampolines [index];
3342 static gpointer
3343 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3345 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3348 static gboolean
3349 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3351 if (mono_llvm_only)
3352 return FALSE;
3354 gpointer *imt = (gpointer*)vt;
3355 imt -= MONO_IMT_SIZE;
3357 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3360 static gboolean
3361 is_callee_gsharedvt_variable (gpointer addr)
3363 MonoJitInfo *ji;
3364 gboolean callee_gsharedvt;
3366 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3367 g_assert (ji);
3368 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3369 if (callee_gsharedvt)
3370 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3371 return callee_gsharedvt;
3374 gpointer
3375 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3377 gpointer arg = NULL;
3379 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3380 arg = mini_method_get_rgctx (method);
3383 * Avoid adding gsharedvt in wrappers since they might not exist if
3384 * this delegate is called through a gsharedvt delegate invoke wrapper.
3385 * Instead, encode that the method is gsharedvt in del->extra_arg,
3386 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3388 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3389 g_assert ((((mgreg_t)arg) & 1) == 0);
3390 arg = (gpointer)(((mgreg_t)arg) | 1);
3392 return arg;
3395 void
3396 mini_init_delegate (MonoDelegate *del)
3398 if (mono_use_interpreter)
3399 mini_get_interp_callbacks ()->init_delegate (del);
3400 else if (mono_llvm_only)
3401 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3404 char*
3405 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3407 int abs_offset;
3409 abs_offset = offset;
3410 if (abs_offset < 0)
3411 abs_offset = - abs_offset;
3412 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3415 gpointer
3416 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3418 gboolean is_virtual_generic, is_interface, load_imt_reg;
3419 int offset, idx;
3421 static guint8 **cache = NULL;
3422 static int cache_size = 0;
3424 if (!method)
3425 return NULL;
3427 if (MONO_TYPE_ISSTRUCT (sig->ret))
3428 return NULL;
3430 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3431 is_interface = mono_class_is_interface (method->klass);
3432 load_imt_reg = is_virtual_generic || is_interface;
3434 if (is_interface)
3435 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3436 else
3437 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3439 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3440 g_assert (idx >= 0);
3442 /* Resize the cache to idx + 1 */
3443 if (cache_size < idx + 1) {
3444 mono_jit_lock ();
3445 if (cache_size < idx + 1) {
3446 guint8 **new_cache;
3447 int new_cache_size = idx + 1;
3449 new_cache = g_new0 (guint8*, new_cache_size);
3450 if (cache)
3451 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3452 g_free (cache);
3454 mono_memory_barrier ();
3455 cache = new_cache;
3456 cache_size = new_cache_size;
3458 mono_jit_unlock ();
3461 if (cache [idx])
3462 return cache [idx];
3464 /* FIXME Support more cases */
3465 if (mono_aot_only) {
3466 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3467 g_assert (cache [idx]);
3468 } else {
3469 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3471 return cache [idx];
3475 * mini_parse_debug_option:
3476 * @option: The option to parse.
3478 * Parses debug options for the mono runtime. The options are the same as for
3479 * the MONO_DEBUG environment variable.
3482 gboolean
3483 mini_parse_debug_option (const char *option)
3485 if (!strcmp (option, "handle-sigint"))
3486 mini_debug_options.handle_sigint = TRUE;
3487 else if (!strcmp (option, "keep-delegates"))
3488 mini_debug_options.keep_delegates = TRUE;
3489 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3490 mini_debug_options.reverse_pinvoke_exceptions = TRUE;
3491 else if (!strcmp (option, "collect-pagefault-stats"))
3492 mini_debug_options.collect_pagefault_stats = TRUE;
3493 else if (!strcmp (option, "break-on-unverified"))
3494 mini_debug_options.break_on_unverified = TRUE;
3495 else if (!strcmp (option, "no-gdb-backtrace"))
3496 mini_debug_options.no_gdb_backtrace = TRUE;
3497 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3498 mini_debug_options.suspend_on_native_crash = TRUE;
3499 else if (!strcmp (option, "suspend-on-exception"))
3500 mini_debug_options.suspend_on_exception = TRUE;
3501 else if (!strcmp (option, "suspend-on-unhandled"))
3502 mini_debug_options.suspend_on_unhandled = TRUE;
3503 else if (!strcmp (option, "dont-free-domains"))
3504 mono_dont_free_domains = TRUE;
3505 else if (!strcmp (option, "dyn-runtime-invoke"))
3506 mini_debug_options.dyn_runtime_invoke = TRUE;
3507 else if (!strcmp (option, "gdb"))
3508 mini_debug_options.gdb = TRUE;
3509 else if (!strcmp (option, "lldb"))
3510 mini_debug_options.lldb = TRUE;
3511 else if (!strcmp (option, "explicit-null-checks"))
3512 mini_debug_options.explicit_null_checks = TRUE;
3513 else if (!strcmp (option, "gen-seq-points"))
3514 mini_debug_options.gen_sdb_seq_points = TRUE;
3515 else if (!strcmp (option, "gen-compact-seq-points"))
3516 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3517 else if (!strcmp (option, "no-compact-seq-points"))
3518 mini_debug_options.no_seq_points_compact_data = TRUE;
3519 else if (!strcmp (option, "single-imm-size"))
3520 mini_debug_options.single_imm_size = TRUE;
3521 else if (!strcmp (option, "init-stacks"))
3522 mini_debug_options.init_stacks = TRUE;
3523 else if (!strcmp (option, "casts"))
3524 mini_debug_options.better_cast_details = TRUE;
3525 else if (!strcmp (option, "soft-breakpoints"))
3526 mini_debug_options.soft_breakpoints = TRUE;
3527 else if (!strcmp (option, "check-pinvoke-callconv"))
3528 mini_debug_options.check_pinvoke_callconv = TRUE;
3529 else if (!strcmp (option, "use-fallback-tls"))
3530 mini_debug_options.use_fallback_tls = TRUE;
3531 else if (!strcmp (option, "debug-domain-unload"))
3532 mono_enable_debug_domain_unload (TRUE);
3533 else if (!strcmp (option, "partial-sharing"))
3534 mono_set_partial_sharing_supported (TRUE);
3535 else if (!strcmp (option, "align-small-structs"))
3536 mono_align_small_structs = TRUE;
3537 else if (!strcmp (option, "native-debugger-break"))
3538 mini_debug_options.native_debugger_break = TRUE;
3539 else if (!strcmp (option, "disable_omit_fp"))
3540 mini_debug_options.disable_omit_fp = TRUE;
3541 else
3542 return FALSE;
3544 return TRUE;
3547 static void
3548 mini_parse_debug_options (void)
3550 char *options = g_getenv ("MONO_DEBUG");
3551 gchar **args, **ptr;
3553 if (!options)
3554 return;
3556 args = g_strsplit (options, ",", -1);
3557 g_free (options);
3559 for (ptr = args; ptr && *ptr; ptr++) {
3560 const char *arg = *ptr;
3562 if (!mini_parse_debug_option (arg)) {
3563 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3564 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'\n");
3565 exit (1);
3569 g_strfreev (args);
3572 MonoDebugOptions *
3573 mini_get_debug_options (void)
3575 return &mini_debug_options;
3578 static gpointer
3579 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3581 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3582 gpointer* desc = NULL;
3584 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3585 return desc;
3586 #if defined(__mono_ppc64__)
3587 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3589 desc [0] = addr;
3590 desc [1] = NULL;
3591 desc [2] = NULL;
3592 # endif
3593 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3594 return desc;
3595 #else
3596 return addr;
3597 #endif
3600 static gpointer
3601 mini_get_addr_from_ftnptr (gpointer descr)
3603 #if defined(PPC_USES_FUNCTION_DESCRIPTOR)
3604 return *(gpointer*)descr;
3605 #else
3606 return descr;
3607 #endif
3610 static void
3611 register_jit_stats (void)
3613 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3614 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3615 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3616 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3617 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3618 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3619 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);
3620 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3621 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3622 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3623 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3624 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3625 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3626 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3627 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3628 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3629 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3630 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3631 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3632 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3633 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3634 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3635 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3636 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3637 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3638 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3639 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3640 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3641 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3642 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3643 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3644 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3645 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3646 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3647 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3648 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3649 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3650 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3651 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3652 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3653 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3654 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3655 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3656 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3657 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3658 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3659 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3660 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3661 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3662 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3663 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3664 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3665 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3666 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3667 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3668 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3669 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3670 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3671 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3672 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3673 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3676 static void runtime_invoke_info_free (gpointer value);
3678 static gint
3679 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3681 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3682 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3684 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3687 static guint
3688 class_method_pair_hash (gconstpointer data)
3690 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3692 return (gsize)pair->klass ^ (gsize)pair->method;
3695 static void
3696 mini_create_jit_domain_info (MonoDomain *domain)
3698 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3700 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3701 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3702 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3703 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3704 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3705 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3706 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3707 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3708 mono_jit_code_hash_init (&info->interp_code_hash);
3710 domain->runtime_info = info;
3713 static void
3714 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3716 MonoJumpList *jlist = (MonoJumpList *)value;
3717 g_slist_free (jlist->list);
3720 static void
3721 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3723 GSList *list = (GSList *)value;
3724 g_slist_free (list);
3727 static void
3728 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3730 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3731 mono_code_manager_destroy (di->code_mp);
3732 g_free (di);
3735 static void
3736 runtime_invoke_info_free (gpointer value)
3738 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3740 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3741 if (info->dyn_call_info)
3742 mono_arch_dyn_call_free (info->dyn_call_info);
3743 #endif
3744 g_free (info);
3747 static void
3748 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3750 g_slist_free (value);
3753 static void
3754 mini_free_jit_domain_info (MonoDomain *domain)
3756 MonoJitDomainInfo *info = domain_jit_info (domain);
3758 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3759 g_hash_table_destroy (info->jump_target_hash);
3760 if (info->jump_target_got_slot_hash) {
3761 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3762 g_hash_table_destroy (info->jump_target_got_slot_hash);
3764 if (info->dynamic_code_hash) {
3765 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3766 g_hash_table_destroy (info->dynamic_code_hash);
3768 if (info->method_code_hash)
3769 g_hash_table_destroy (info->method_code_hash);
3770 g_hash_table_destroy (info->jump_trampoline_hash);
3771 g_hash_table_destroy (info->jit_trampoline_hash);
3772 g_hash_table_destroy (info->delegate_trampoline_hash);
3773 if (info->static_rgctx_trampoline_hash)
3774 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3775 if (info->mrgctx_hash)
3776 g_hash_table_destroy (info->mrgctx_hash);
3777 if (info->method_rgctx_hash)
3778 g_hash_table_destroy (info->method_rgctx_hash);
3779 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3780 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3781 g_hash_table_destroy (info->seq_points);
3782 g_hash_table_destroy (info->arch_seq_points);
3783 if (info->agent_info)
3784 mono_debugger_agent_free_domain_info (domain);
3785 if (info->gsharedvt_arg_tramp_hash)
3786 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3787 if (info->llvm_jit_callees) {
3788 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3789 g_hash_table_destroy (info->llvm_jit_callees);
3791 mono_internal_hash_table_destroy (&info->interp_code_hash);
3792 #ifdef ENABLE_LLVM
3793 mono_llvm_free_domain_info (domain);
3794 #endif
3796 g_free (domain->runtime_info);
3797 domain->runtime_info = NULL;
3800 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3802 static void
3803 code_manager_chunk_new (void *chunk, int size)
3805 mono_arch_code_chunk_new (chunk, size);
3808 static void
3809 code_manager_chunk_destroy (void *chunk)
3811 mono_arch_code_chunk_destroy (chunk);
3814 #endif
3816 #ifdef ENABLE_LLVM
3817 static gboolean
3818 llvm_init_inner (void)
3820 if (!mono_llvm_load (NULL))
3821 return FALSE;
3823 mono_llvm_init ();
3824 return TRUE;
3826 #endif
3829 * mini_llvm_init:
3831 * Load and initialize LLVM support.
3832 * Return TRUE on success.
3834 gboolean
3835 mini_llvm_init (void)
3837 #ifdef ENABLE_LLVM
3838 static gboolean llvm_inited;
3839 static gboolean init_result;
3841 mono_loader_lock_if_inited ();
3842 if (!llvm_inited) {
3843 init_result = llvm_init_inner ();
3844 llvm_inited = TRUE;
3846 mono_loader_unlock_if_inited ();
3847 return init_result;
3848 #else
3849 return FALSE;
3850 #endif
3853 void
3854 mini_add_profiler_argument (const char *desc)
3856 if (!profile_options)
3857 profile_options = g_ptr_array_new ();
3859 g_ptr_array_add (profile_options, (gpointer) desc);
3863 static MonoEECallbacks interp_cbs = {0};
3865 void
3866 mini_install_interp_callbacks (MonoEECallbacks *cbs)
3868 memcpy (&interp_cbs, cbs, sizeof (MonoEECallbacks));
3871 MonoEECallbacks *
3872 mini_get_interp_callbacks (void)
3874 return &interp_cbs;
3878 mono_ee_api_version (void)
3880 return MONO_EE_API_VERSION;
3883 MonoDomain *
3884 mini_init (const char *filename, const char *runtime_version)
3886 ERROR_DECL (error);
3887 MonoDomain *domain;
3888 MonoRuntimeCallbacks callbacks;
3889 MonoThreadInfoRuntimeCallbacks ticallbacks;
3890 MonoCodeManagerCallbacks code_manager_callbacks;
3892 MONO_VES_INIT_BEGIN ();
3894 CHECKED_MONO_INIT ();
3896 #if defined(__linux__)
3897 if (access ("/proc/self/maps", F_OK) != 0) {
3898 g_print ("Mono requires /proc to be mounted.\n");
3899 exit (1);
3901 #endif
3903 mono_interp_stub_init ();
3904 #ifndef DISABLE_INTERPRETER
3905 if (mono_use_interpreter)
3906 mono_ee_interp_init (mono_interp_opts_string);
3907 #endif
3909 mono_os_mutex_init_recursive (&jit_mutex);
3911 mono_cross_helpers_run ();
3913 mono_counters_init ();
3915 mini_jit_init ();
3917 mini_jit_init_job_control ();
3919 /* Happens when using the embedding interface */
3920 if (!default_opt_set)
3921 default_opt = mono_parse_default_optimizations (NULL);
3923 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3924 if (mono_aot_only)
3925 mono_set_generic_sharing_vt_supported (TRUE);
3926 #else
3927 if (mono_llvm_only)
3928 mono_set_generic_sharing_vt_supported (TRUE);
3929 #endif
3931 mono_tls_init_runtime_keys ();
3933 if (!global_codeman)
3934 global_codeman = mono_code_manager_new ();
3936 memset (&callbacks, 0, sizeof (callbacks));
3937 callbacks.create_ftnptr = mini_create_ftnptr;
3938 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3939 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3940 callbacks.set_cast_details = mono_set_cast_details;
3941 callbacks.debug_log = mono_debugger_agent_debug_log;
3942 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3943 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3944 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3945 callbacks.imt_entry_inited = mini_imt_entry_inited;
3946 callbacks.init_delegate = mini_init_delegate;
3947 #define JIT_INVOKE_WORKS
3948 #ifdef JIT_INVOKE_WORKS
3949 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3950 #endif
3951 #define JIT_TRAMPOLINES_WORK
3952 #ifdef JIT_TRAMPOLINES_WORK
3953 callbacks.compile_method = mono_jit_compile_method;
3954 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3955 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3956 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3957 callbacks.free_method = mono_jit_free_method;
3958 #ifndef DISABLE_REMOTING
3959 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3960 #endif
3961 #endif
3962 #ifndef DISABLE_REMOTING
3963 if (mono_use_interpreter)
3964 callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke;
3965 #endif
3966 callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;
3968 mono_install_callbacks (&callbacks);
3970 memset (&ticallbacks, 0, sizeof (ticallbacks));
3971 ticallbacks.setup_async_callback = mono_setup_async_callback;
3972 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3973 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3974 ticallbacks.thread_state_init = mono_thread_state_init;
3976 #ifndef HOST_WIN32
3977 mono_w32handle_init ();
3978 #endif
3980 mono_thread_info_runtime_init (&ticallbacks);
3982 if (g_hasenv ("MONO_DEBUG")) {
3983 mini_parse_debug_options ();
3986 mono_code_manager_init ();
3988 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3989 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3990 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3991 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3992 #endif
3993 mono_code_manager_install_callbacks (&code_manager_callbacks);
3995 mono_hwcap_init ();
3997 mono_arch_cpu_init ();
3999 mono_arch_init ();
4001 mono_unwind_init ();
4003 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
4004 mono_lldb_init ("");
4005 mono_dont_free_domains = TRUE;
4008 #ifdef XDEBUG_ENABLED
4009 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
4010 if (mono_xdebug) {
4011 mono_xdebug_init (mono_xdebug);
4012 g_free (mono_xdebug);
4013 /* So methods for multiple domains don't have the same address */
4014 mono_dont_free_domains = TRUE;
4015 mono_using_xdebug = TRUE;
4016 } else if (mini_get_debug_options ()->gdb) {
4017 mono_xdebug_init ((char*)"gdb");
4018 mono_dont_free_domains = TRUE;
4019 mono_using_xdebug = TRUE;
4021 #endif
4023 #ifdef ENABLE_LLVM
4024 if (mono_use_llvm) {
4025 if (!mono_llvm_load (NULL)) {
4026 mono_use_llvm = FALSE;
4027 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
4030 if (mono_use_llvm)
4031 mono_llvm_init ();
4032 #endif
4034 mono_trampolines_init ();
4036 if (default_opt & MONO_OPT_AOT)
4037 mono_aot_init ();
4039 mono_debugger_agent_init ();
4041 #ifdef TARGET_WASM
4042 mono_wasm_debugger_init ();
4043 #endif
4045 #ifdef MONO_ARCH_GSHARED_SUPPORTED
4046 mono_set_generic_sharing_supported (TRUE);
4047 #endif
4049 mono_thread_info_signals_init ();
4051 #ifndef MONO_CROSS_COMPILE
4052 mono_runtime_install_handlers ();
4053 #endif
4054 mono_threads_install_cleanup (mini_thread_cleanup);
4056 #ifdef JIT_TRAMPOLINES_WORK
4057 mono_install_create_domain_hook (mini_create_jit_domain_info);
4058 mono_install_free_domain_hook (mini_free_jit_domain_info);
4059 #endif
4060 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
4061 mono_install_get_class_from_name (mono_aot_get_class_from_name);
4062 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
4064 mono_profiler_state.context_enable = mini_profiler_context_enable;
4065 mono_profiler_state.context_get_this = mini_profiler_context_get_this;
4066 mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
4067 mono_profiler_state.context_get_local = mini_profiler_context_get_local;
4068 mono_profiler_state.context_get_result = mini_profiler_context_get_result;
4069 mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
4071 if (profile_options)
4072 for (guint i = 0; i < profile_options->len; i++)
4073 mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
4075 mono_profiler_started ();
4077 if (mini_debug_options.collect_pagefault_stats)
4078 mono_aot_set_make_unreadable (TRUE);
4080 if (runtime_version)
4081 domain = mono_init_version (filename, runtime_version);
4082 else
4083 domain = mono_init_from_assembly (filename, filename);
4085 if (mono_aot_only) {
4086 /* This helps catch code allocation requests */
4087 mono_code_manager_set_read_only (domain->code_mp);
4088 mono_marshal_use_aot_wrappers (TRUE);
4091 if (mono_llvm_only) {
4092 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
4093 mono_set_always_build_imt_trampolines (TRUE);
4094 } else if (mono_aot_only) {
4095 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
4096 } else {
4097 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
4100 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
4101 mono_arch_finish_init ();
4103 mono_icall_init ();
4105 /* This must come after mono_init () in the aot-only case */
4106 mono_exceptions_init ();
4108 /* This should come after mono_init () too */
4109 mini_gc_init ();
4111 #ifndef DISABLE_JIT
4112 mono_create_helper_signatures ();
4113 #endif
4115 register_jit_stats ();
4117 #define JIT_CALLS_WORK
4118 #ifdef JIT_CALLS_WORK
4119 /* Needs to be called here since register_jit_icall depends on it */
4120 mono_marshal_init ();
4122 mono_arch_register_lowlevel_calls ();
4124 register_icalls ();
4126 mono_generic_sharing_init ();
4127 #endif
4129 #ifdef MONO_ARCH_SIMD_INTRINSICS
4130 mono_simd_intrinsics_init ();
4131 #endif
4133 mono_tasklets_init ();
4135 register_trampolines (domain);
4137 if (mono_compile_aot)
4139 * Avoid running managed code when AOT compiling, since the platform
4140 * might only support aot-only execution.
4142 mono_runtime_set_no_exec (TRUE);
4144 mono_mem_account_register_counters ();
4146 #define JIT_RUNTIME_WORKS
4147 #ifdef JIT_RUNTIME_WORKS
4148 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
4149 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, error);
4150 mono_error_assert_ok (error);
4151 mono_thread_attach (domain);
4152 MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
4153 #endif
4155 if (mono_profiler_sampling_enabled ())
4156 mono_runtime_setup_stat_profiler ();
4158 MONO_PROFILER_RAISE (runtime_initialized, ());
4160 MONO_VES_INIT_END ();
4162 return domain;
4165 static void
4166 register_icalls (void)
4168 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4169 ves_icall_get_frame_info);
4170 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4171 ves_icall_get_trace);
4172 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4173 mono_runtime_install_handlers);
4174 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
4175 mono_runtime_cleanup_handlers);
4177 #if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
4178 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
4179 mono_debugger_agent_unhandled_exception);
4180 #endif
4183 * It's important that we pass `TRUE` as the last argument here, as
4184 * it causes the JIT to omit a wrapper for these icalls. If the JIT
4185 * *did* emit a wrapper, we'd be looking at infinite recursion since
4186 * the wrapper would call the icall which would call the wrapper and
4187 * so on.
4189 register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
4190 register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
4191 register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
4193 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4194 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4195 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4196 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4197 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4198 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4200 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4201 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4202 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4203 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4204 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4205 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4206 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4207 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4208 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4210 // FIXME: This is broken
4211 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4212 #endif
4214 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4215 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4216 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4217 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4218 register_icall (ves_icall_thread_finish_async_abort, "ves_icall_thread_finish_async_abort", "void", FALSE);
4219 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4220 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4222 if (mono_threads_are_safepoints_enabled ())
4223 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4225 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4226 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4227 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4228 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4229 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4230 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4231 #endif
4232 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4233 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4234 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4235 #endif
4237 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4238 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4239 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4240 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4241 #endif
4243 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4244 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4245 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4246 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4247 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4248 #endif
4250 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4251 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4252 #endif
4254 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4255 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4256 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4257 #endif
4259 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4260 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4261 #endif
4263 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4264 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4265 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4266 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4267 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4268 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4269 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4272 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4273 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4274 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4275 #endif
4277 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4278 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);
4279 #endif
4280 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4281 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4282 #endif
4283 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4284 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4285 #endif
4286 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4287 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);
4288 #endif
4289 #ifdef MONO_ARCH_EMULATE_FREM
4290 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4291 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4292 #endif
4294 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4295 if (mono_arch_is_soft_float ()) {
4296 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4297 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4298 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4299 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4300 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4301 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4302 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4303 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4304 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4305 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4306 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4307 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4309 #if SIZEOF_VOID_P == 4
4310 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4311 #endif
4313 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4314 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4315 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4316 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4317 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4318 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4319 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4320 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4321 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4322 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4324 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4325 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4326 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4327 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4328 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4330 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4331 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4332 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4333 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4335 #endif
4336 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4338 #ifdef COMPRESSED_INTERFACE_BITMAP
4339 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4340 #endif
4342 #if SIZEOF_REGISTER == 4
4343 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4344 #else
4345 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4346 #endif
4348 /* other jit icalls */
4349 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4350 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4351 "ptr ptr ptr", FALSE);
4352 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4353 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4354 "ptr ptr ptr ptr", FALSE);
4355 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4356 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4357 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4358 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4359 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4360 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4361 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4362 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4363 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4364 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4365 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4366 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4367 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4368 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4369 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4370 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4371 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4372 register_icall (mono_break, "mono_break", NULL, TRUE);
4373 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4374 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4375 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4376 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4377 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4378 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4379 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4380 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4381 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4382 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4383 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4385 //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
4386 register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_range_copy", "void ptr ptr int");
4388 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4389 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4390 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4391 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4392 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4394 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4396 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4397 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4398 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4399 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4401 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4402 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4403 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4404 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4405 /* This needs a wrapper so it can have a preserveall cconv */
4406 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4407 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4408 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4409 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4410 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4411 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4412 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4414 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "int32 obj");
4415 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4416 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4417 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4419 #ifdef TARGET_IOS
4420 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4421 #endif
4422 /* Register tls icalls */
4423 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4424 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4425 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4426 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4427 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4428 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4429 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4430 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4431 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4432 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4435 #ifdef MONO_ARCH_HAS_REGISTER_ICALL
4436 mono_arch_register_icall ();
4437 #endif
4440 MonoJitStats mono_jit_stats = {0};
4443 * Counters of mono_stats and mono_jit_stats can be read without locking here.
4444 * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
4446 MONO_NO_SANITIZE_THREAD
4447 static void
4448 print_jit_stats (void)
4450 if (mono_jit_stats.enabled) {
4451 g_print ("Mono Jit statistics\n");
4452 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio / 100.0,
4453 mono_jit_stats.max_ratio_method);
4454 g_print ("Biggest method: %" G_GINT32_FORMAT " (%s)\n", mono_jit_stats.biggest_method_size,
4455 mono_jit_stats.biggest_method);
4457 g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
4458 g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
4459 g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
4460 g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
4461 g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
4462 g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
4463 g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
4464 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4466 g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
4467 g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
4468 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4470 g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
4471 g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
4472 g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
4473 g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
4475 g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
4476 g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
4477 g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
4478 g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
4479 g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
4480 g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
4481 g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
4482 g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
4484 g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
4485 g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
4486 g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
4488 g_free (mono_jit_stats.max_ratio_method);
4489 mono_jit_stats.max_ratio_method = NULL;
4490 g_free (mono_jit_stats.biggest_method);
4491 mono_jit_stats.biggest_method = NULL;
4495 void
4496 mini_cleanup (MonoDomain *domain)
4498 if (mono_profiler_sampling_enabled ())
4499 mono_runtime_shutdown_stat_profiler ();
4501 MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
4503 #ifndef DISABLE_COM
4504 mono_cominterop_release_all_rcws ();
4505 #endif
4507 #ifndef MONO_CROSS_COMPILE
4509 * mono_domain_finalize () needs to be called early since it needs the
4510 * execution engine still fully working (it may invoke managed finalizers).
4512 mono_domain_finalize (domain, 2000);
4513 #endif
4515 /* This accesses metadata so needs to be called before runtime shutdown */
4516 print_jit_stats ();
4518 #ifndef MONO_CROSS_COMPILE
4519 mono_runtime_cleanup (domain);
4520 #endif
4522 mono_threadpool_cleanup ();
4524 MONO_PROFILER_RAISE (runtime_shutdown_end, ());
4526 mono_profiler_cleanup ();
4528 if (profile_options)
4529 g_ptr_array_free (profile_options, TRUE);
4531 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4533 mono_icall_cleanup ();
4535 mono_runtime_cleanup_handlers ();
4537 #ifndef MONO_CROSS_COMPILE
4538 mono_domain_free (domain, TRUE);
4539 #endif
4541 #ifdef ENABLE_LLVM
4542 if (mono_use_llvm)
4543 mono_llvm_cleanup ();
4544 #endif
4546 mono_aot_cleanup ();
4548 mono_trampolines_cleanup ();
4550 mono_unwind_cleanup ();
4552 mono_code_manager_destroy (global_codeman);
4553 g_free (vtable_trampolines);
4555 mini_jit_cleanup ();
4557 mono_tramp_info_cleanup ();
4559 mono_arch_cleanup ();
4561 mono_generic_sharing_cleanup ();
4563 mono_cleanup ();
4565 mono_trace_cleanup ();
4567 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4569 if (mono_inject_async_exc_method)
4570 mono_method_desc_free (mono_inject_async_exc_method);
4572 mono_tls_free_keys ();
4574 mono_os_mutex_destroy (&jit_mutex);
4576 mono_code_manager_cleanup ();
4578 #ifndef HOST_WIN32
4579 mono_w32handle_cleanup ();
4580 #endif
4583 void
4584 mono_set_defaults (int verbose_level, guint32 opts)
4586 mini_verbose = verbose_level;
4587 mono_set_optimizations (opts);
4590 void
4591 mono_disable_optimizations (guint32 opts)
4593 default_opt &= ~opts;
4596 void
4597 mono_set_optimizations (guint32 opts)
4599 default_opt = opts;
4600 default_opt_set = TRUE;
4601 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4602 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4603 #else
4604 if (mono_llvm_only)
4605 mono_set_generic_sharing_vt_supported (TRUE);
4606 #endif
4609 void
4610 mono_set_verbose_level (guint32 level)
4612 mini_verbose = level;
4616 * mono_get_runtime_build_info:
4617 * The returned string is owned by the caller. The returned string
4618 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4619 * \returns the runtime version + build date in string format.
4621 char*
4622 mono_get_runtime_build_info (void)
4624 if (mono_build_date)
4625 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4626 else
4627 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4630 static void
4631 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4633 GHashTable *assemblies = (GHashTable*)user_data;
4634 MonoImage *image = mono_assembly_get_image (ass);
4635 MonoMethod *method, *invoke;
4636 int i, count = 0;
4638 if (g_hash_table_lookup (assemblies, ass))
4639 return;
4641 g_hash_table_insert (assemblies, ass, ass);
4643 if (mini_verbose > 0)
4644 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4646 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4647 ERROR_DECL (error);
4649 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
4650 if (!method) {
4651 mono_error_cleanup (error); /* FIXME don't swallow the error */
4652 continue;
4654 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4655 continue;
4656 if (method->is_generic || mono_class_is_gtd (method->klass))
4657 continue;
4659 count++;
4660 if (mini_verbose > 1) {
4661 char * desc = mono_method_full_name (method, TRUE);
4662 g_print ("Compiling %d %s\n", count, desc);
4663 g_free (desc);
4665 mono_compile_method_checked (method, error);
4666 if (!is_ok (error)) {
4667 mono_error_cleanup (error); /* FIXME don't swallow the error */
4668 continue;
4670 if (strcmp (method->name, "Finalize") == 0) {
4671 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4672 mono_compile_method_checked (invoke, error);
4673 mono_error_assert_ok (error);
4675 #ifndef DISABLE_REMOTING
4676 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4677 invoke = mono_marshal_get_remoting_invoke_with_check (method, error);
4678 mono_error_assert_ok (error);
4679 mono_compile_method_checked (invoke, error);
4680 mono_error_assert_ok (error);
4682 #endif
4685 /* Load and precompile referenced assemblies as well */
4686 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4687 mono_assembly_load_reference (image, i);
4688 if (image->references [i])
4689 mono_precompile_assembly (image->references [i], assemblies);
4693 void mono_precompile_assemblies ()
4695 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4697 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4699 g_hash_table_destroy (assemblies);
4703 * Used by LLVM.
4704 * Have to export this for AOT.
4706 void
4707 mono_personality (void)
4709 /* Not used */
4710 g_assert_not_reached ();
4714 static MonoBreakPolicy
4715 always_insert_breakpoint (MonoMethod *method)
4717 return MONO_BREAK_POLICY_ALWAYS;
4720 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4723 * mono_set_break_policy:
4724 * \param policy_callback the new callback function
4726 * Allow embedders to decide whether to actually obey breakpoint instructions
4727 * (both break IL instructions and \c Debugger.Break method calls), for example
4728 * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4729 * untrusted or semi-trusted code.
4731 * \p policy_callback will be called every time a break point instruction needs to
4732 * be inserted with the method argument being the method that calls \c Debugger.Break
4733 * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
4734 * if it wants the breakpoint to not be effective in the given method.
4735 * \c MONO_BREAK_POLICY_ALWAYS is the default.
4737 void
4738 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4740 if (policy_callback)
4741 break_policy_func = policy_callback;
4742 else
4743 break_policy_func = always_insert_breakpoint;
4746 gboolean
4747 mini_should_insert_breakpoint (MonoMethod *method)
4749 switch (break_policy_func (method)) {
4750 case MONO_BREAK_POLICY_ALWAYS:
4751 return TRUE;
4752 case MONO_BREAK_POLICY_NEVER:
4753 return FALSE;
4754 case MONO_BREAK_POLICY_ON_DBG:
4755 g_warning ("mdb no longer supported");
4756 return FALSE;
4757 default:
4758 g_warning ("Incorrect value returned from break policy callback");
4759 return FALSE;
4763 // Custom handlers currently only implemented by Windows.
4764 #ifndef HOST_WIN32
4765 gboolean
4766 mono_runtime_install_custom_handlers (const char *handlers)
4768 return FALSE;
4771 void
4772 mono_runtime_install_custom_handlers_usage (void)
4774 fprintf (stdout,
4775 "Custom Handlers:\n"
4776 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4777 " separated list of available handlers to install.\n"
4778 "\n"
4779 "No handlers supported on current platform.\n");
4781 #endif /* HOST_WIN32 */