Fix compilation issues.
[mono-project.git] / mono / mini / mini-runtime.c
bloba6ed4425da89809a080af135922e9280fff308c0
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.h"
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/attach.h>
51 #include <mono/metadata/runtime.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/utils/mono-math.h>
55 #include <mono/utils/mono-compiler.h>
56 #include <mono/utils/mono-counters.h>
57 #include <mono/utils/mono-error-internals.h>
58 #include <mono/utils/mono-logger-internals.h>
59 #include <mono/utils/mono-mmap.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-tls.h>
62 #include <mono/utils/mono-hwcap.h>
63 #include <mono/utils/dtrace.h>
64 #include <mono/utils/mono-signal-handler.h>
65 #include <mono/utils/mono-threads.h>
66 #include <mono/utils/mono-threads-coop.h>
67 #include <mono/utils/checked-build.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"
80 #include "jit-icalls.h"
82 #include "mini-gc.h"
83 #include "mini-llvm.h"
84 #include "debugger-agent.h"
85 #include "lldb.h"
87 #ifdef MONO_ARCH_LLVM_SUPPORTED
88 #ifdef ENABLE_LLVM
89 #include "mini-llvm-cpp.h"
90 #include "llvm-jit.h"
91 #endif
92 #endif
94 #ifdef ENABLE_INTERPRETER
95 #include "interp/interp.h"
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;
121 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
122 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
123 static mono_mutex_t jit_mutex;
125 static MonoCodeManager *global_codeman;
127 MonoDebugOptions debug_options;
129 #ifdef VALGRIND_JIT_REGISTER_MAP
130 int valgrind_register;
131 #endif
132 GList* mono_aot_paths;
134 static gboolean mini_enable_profiler = FALSE;
135 static char* mini_profiler_options = NULL;
137 static GSList *tramp_infos;
139 static void register_icalls (void);
141 static gboolean mini_profiler_enabled (void) { return mini_enable_profiler; }
142 static const char* mini_profiler_get_options (void) { return mini_profiler_options; }
144 gboolean
145 mono_running_on_valgrind (void)
147 #ifndef HOST_WIN32
148 if (RUNNING_ON_VALGRIND){
149 #ifdef VALGRIND_JIT_REGISTER_MAP
150 valgrind_register = TRUE;
151 #endif
152 return TRUE;
153 } else
154 #endif
155 return FALSE;
158 typedef struct {
159 void *ip;
160 MonoMethod *method;
161 } FindTrampUserData;
163 static void
164 find_tramp (gpointer key, gpointer value, gpointer user_data)
166 FindTrampUserData *ud = (FindTrampUserData*)user_data;
168 if (value == ud->ip)
169 ud->method = (MonoMethod*)key;
172 /* debug function */
173 G_GNUC_UNUSED static char*
174 get_method_from_ip (void *ip)
176 MonoJitInfo *ji;
177 MonoMethod *method;
178 char *method_name;
179 char *res;
180 MonoDomain *domain = mono_domain_get ();
181 MonoDebugSourceLocation *location;
182 FindTrampUserData user_data;
184 if (!domain)
185 domain = mono_get_root_domain ();
187 ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
188 if (!ji) {
189 user_data.ip = ip;
190 user_data.method = NULL;
191 mono_domain_lock (domain);
192 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
193 mono_domain_unlock (domain);
194 if (user_data.method) {
195 char *mname = mono_method_full_name (user_data.method, TRUE);
196 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
197 g_free (mname);
198 return res;
200 else
201 return NULL;
202 } else if (ji->is_trampoline) {
203 res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
204 return res;
207 method = jinfo_get_method (ji);
208 method_name = mono_method_full_name (method, TRUE);
209 /* FIXME: unused ? */
210 location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
212 res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
214 mono_debug_free_source_location (location);
215 g_free (method_name);
217 return res;
221 * mono_pmip:
222 * \param ip an instruction pointer address
224 * This method is used from a debugger to get the name of the
225 * method at address \p ip. This routine is typically invoked from
226 * a debugger like this:
228 * (gdb) print mono_pmip ($pc)
230 * \returns the name of the method at address \p ip.
232 G_GNUC_UNUSED char *
233 mono_pmip (void *ip)
235 return get_method_from_ip (ip);
239 * mono_print_method_from_ip:
240 * \param ip an instruction pointer address
242 * This method is used from a debugger to get the name of the
243 * method at address \p ip.
245 * This prints the name of the method at address \p ip in the standard
246 * output. Unlike \c mono_pmip which returns a string, this routine
247 * prints the value on the standard output.
249 MONO_ATTR_USED void
250 mono_print_method_from_ip (void *ip)
252 MonoJitInfo *ji;
253 char *method;
254 MonoDebugSourceLocation *source;
255 MonoDomain *domain = mono_domain_get ();
256 MonoDomain *target_domain = mono_domain_get ();
257 FindTrampUserData user_data;
258 MonoGenericSharingContext*gsctx;
259 const char *shared_type;
261 if (!domain)
262 domain = mono_get_root_domain ();
263 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
264 if (ji && ji->is_trampoline) {
265 MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
267 printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
268 return;
271 if (!ji) {
272 user_data.ip = ip;
273 user_data.method = NULL;
274 mono_domain_lock (domain);
275 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
276 mono_domain_unlock (domain);
278 if (user_data.method) {
279 char *mname = mono_method_full_name (user_data.method, TRUE);
280 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
281 g_free (mname);
282 return;
285 g_print ("No method at %p\n", ip);
286 fflush (stdout);
287 return;
289 method = mono_method_full_name (jinfo_get_method (ji), TRUE);
290 source = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
292 gsctx = mono_jit_info_get_generic_sharing_context (ji);
293 shared_type = "";
294 if (gsctx) {
295 if (gsctx->is_gsharedvt)
296 shared_type = "gsharedvt ";
297 else
298 shared_type = "gshared ";
301 g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
303 if (source)
304 g_print ("%s:%d\n", source->source_file, source->row);
305 fflush (stdout);
307 mono_debug_free_source_location (source);
308 g_free (method);
312 * mono_method_same_domain:
314 * Determine whenever two compiled methods are in the same domain, thus
315 * the address of the callee can be embedded in the caller.
317 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
319 MonoMethod *cmethod;
321 if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
322 return FALSE;
325 * If the call was made from domain-neutral to domain-specific
326 * code, we can't patch the call site.
328 if (caller->domain_neutral && !callee->domain_neutral)
329 return FALSE;
331 cmethod = jinfo_get_method (caller);
332 if ((cmethod->klass == mono_defaults.appdomain_class) &&
333 (strstr (cmethod->name, "InvokeInDomain"))) {
334 /* The InvokeInDomain methods change the current appdomain */
335 return FALSE;
338 return TRUE;
342 * mono_global_codeman_reserve:
344 * Allocate code memory from the global code manager.
346 void *mono_global_codeman_reserve (int size)
348 void *ptr;
350 if (mono_aot_only)
351 g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
353 if (!global_codeman) {
354 /* This can happen during startup */
355 global_codeman = mono_code_manager_new ();
356 return mono_code_manager_reserve (global_codeman, size);
358 else {
359 mono_jit_lock ();
360 ptr = mono_code_manager_reserve (global_codeman, size);
361 mono_jit_unlock ();
362 return ptr;
366 /* The callback shouldn't take any locks */
367 void
368 mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
370 mono_jit_lock ();
371 mono_code_manager_foreach (global_codeman, func, user_data);
372 mono_jit_unlock ();
375 #if defined(__native_client_codegen__) && defined(__native_client__)
376 void
377 mono_nacl_gc()
379 #ifdef __native_client_gc__
380 __nacl_suspend_thread_if_needed();
381 #endif
383 #endif /* __native_client__ */
386 * mono_create_unwind_op:
388 * Create an unwind op with the given parameters.
390 MonoUnwindOp*
391 mono_create_unwind_op (int when, int tag, int reg, int val)
393 MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
395 op->op = tag;
396 op->reg = reg;
397 op->val = val;
398 op->when = when;
400 return op;
403 MonoJumpInfoToken *
404 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
406 MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
407 res->image = image;
408 res->token = token;
409 res->has_context = context != NULL;
410 if (context)
411 memcpy (&res->context, context, sizeof (MonoGenericContext));
413 return res;
416 MonoJumpInfoToken *
417 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
419 return mono_jump_info_token_new2 (mp, image, token, NULL);
423 * mono_tramp_info_create:
425 * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
426 * of JI, and UNWIND_OPS.
428 MonoTrampInfo*
429 mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
431 MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
433 info->name = g_strdup ((char*)name);
434 info->code = code;
435 info->code_size = code_size;
436 info->ji = ji;
437 info->unwind_ops = unwind_ops;
439 return info;
442 void
443 mono_tramp_info_free (MonoTrampInfo *info)
445 g_free (info->name);
447 // FIXME: ji
448 mono_free_unwind_info (info->unwind_ops);
449 if (info->owns_uw_info)
450 g_free (info->uw_info);
451 g_free (info);
454 static void
455 register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
457 MonoJitInfo *ji;
459 ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
460 mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
461 ji->d.tramp_info = info;
462 ji->is_trampoline = TRUE;
464 ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
466 mono_jit_info_table_add (domain, ji);
470 * mono_tramp_info_register:
472 * Remember INFO for use by xdebug, mono_print_method_from_ip (), jit maps, etc.
473 * INFO can be NULL.
474 * Frees INFO.
476 static void
477 mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
479 MonoTrampInfo *copy;
481 if (!info)
482 return;
484 if (!domain)
485 domain = mono_get_root_domain ();
487 copy = g_new0 (MonoTrampInfo, 1);
488 copy->code = info->code;
489 copy->code_size = info->code_size;
490 copy->name = g_strdup (info->name);
492 if (info->unwind_ops) {
493 copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
494 copy->owns_uw_info = TRUE;
495 } else {
496 /* Trampolines from aot have the unwind ops already encoded */
497 copy->uw_info = info->uw_info;
498 copy->uw_info_len = info->uw_info_len;
501 mono_jit_lock ();
502 tramp_infos = g_slist_prepend (tramp_infos, copy);
503 mono_jit_unlock ();
505 mono_save_trampoline_xdebug_info (info);
506 mono_lldb_save_trampoline_info (info);
508 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
509 if (!aot)
510 mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
511 #endif
513 /* Only register trampolines that have unwind infos */
514 if (mono_get_root_domain () && copy->uw_info)
515 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;
574 static gboolean inited;
575 static char *value;
577 count ++;
579 if (!inited) {
580 value = g_getenv ("COUNT");
581 inited = TRUE;
584 if (!value)
585 return TRUE;
587 int int_val = atoi (value);
588 g_free (value);
590 if (count == int_val)
591 break_count ();
593 if (count > int_val)
594 return FALSE;
596 return TRUE;
599 gconstpointer
600 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
602 MonoError error;
603 char *name;
604 MonoMethod *wrapper;
605 gconstpointer trampoline;
606 MonoDomain *domain = mono_get_root_domain ();
607 gboolean check_exc = TRUE;
609 if (callinfo->wrapper)
610 return callinfo->wrapper;
612 if (callinfo->trampoline)
613 return callinfo->trampoline;
615 if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
616 /* This icall is used to check for exceptions, so don't check in the wrapper */
617 check_exc = FALSE;
619 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
620 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
621 g_free (name);
623 if (do_compile) {
624 trampoline = mono_compile_method_checked (wrapper, &error);
625 mono_error_assert_ok (&error);
626 } else {
628 trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
629 mono_error_assert_ok (&error);
630 trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
633 mono_loader_lock ();
634 if (!callinfo->trampoline) {
635 mono_register_jit_icall_wrapper (callinfo, trampoline);
636 callinfo->trampoline = trampoline;
638 mono_loader_unlock ();
640 return callinfo->trampoline;
643 gconstpointer
644 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
646 return mono_icall_get_wrapper_full (callinfo, FALSE);
649 static MonoJitDynamicMethodInfo*
650 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
652 MonoJitDynamicMethodInfo *res;
654 if (domain_jit_info (domain)->dynamic_code_hash)
655 res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
656 else
657 res = NULL;
658 return res;
661 static void
662 register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw)
664 #ifndef DISABLE_JIT
665 mini_register_opcode_emulation (opcode, name, sigstr, func, symbol, no_throw);
666 #else
667 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
669 g_assert (!sig->hasthis);
670 g_assert (sig->param_count < 3);
672 /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
673 mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, 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, FALSE, 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, FALSE, 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, 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_jit_thread_attach:
797 * Called by Xamarin.Mac and other products. Attach thread to runtime if
798 * needed and switch to @domain.
800 * @return the original domain which needs to be restored, or NULL.
802 MonoDomain*
803 mono_jit_thread_attach (MonoDomain *domain)
805 MonoDomain *orig;
806 gboolean attached;
808 g_assert (!mono_threads_is_coop_enabled ());
810 if (!domain) {
811 /* Happens when called from AOTed code which is only used in the root domain. */
812 domain = mono_get_root_domain ();
815 g_assert (domain);
817 attached = mono_tls_get_jit_tls () != NULL;
819 if (!attached) {
820 mono_thread_attach (domain);
822 // #678164
823 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
826 orig = mono_domain_get ();
827 if (orig != domain)
828 mono_domain_set (domain, TRUE);
830 return orig != domain ? orig : NULL;
834 * mono_jit_set_domain:
836 * Set domain to @domain if @domain is not null
838 void
839 mono_jit_set_domain (MonoDomain *domain)
841 g_assert (!mono_threads_is_coop_enabled ());
843 if (domain)
844 mono_domain_set (domain, TRUE);
848 * mono_thread_abort:
849 * \param obj exception object
850 * Abort the thread, print exception information and stack trace
852 static void
853 mono_thread_abort (MonoObject *obj)
855 /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
857 /* handle_remove should be eventually called for this thread, too
858 g_free (jit_tls);*/
860 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY) ||
861 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
862 mono_thread_exit ();
863 } else {
864 mono_invoke_unhandled_exception_hook (obj);
868 static void*
869 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
871 MonoJitTlsData *jit_tls;
872 MonoLMF *lmf;
874 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
875 if (jit_tls)
876 return jit_tls;
878 jit_tls = g_new0 (MonoJitTlsData, 1);
880 jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
881 jit_tls->end_of_stack = stack_start;
883 mono_set_jit_tls (jit_tls);
885 lmf = g_new0 (MonoLMF, 1);
886 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
888 jit_tls->first_lmf = lmf;
890 mono_set_lmf_addr (&jit_tls->lmf);
892 jit_tls->lmf = lmf;
894 #ifdef MONO_ARCH_HAVE_TLS_INIT
895 mono_arch_tls_init ();
896 #endif
898 mono_setup_altstack (jit_tls);
900 return jit_tls;
903 static void
904 free_jit_tls_data (MonoJitTlsData *jit_tls)
906 mono_arch_free_jit_tls_data (jit_tls);
907 mono_free_altstack (jit_tls);
909 g_free (jit_tls->first_lmf);
910 g_free (jit_tls);
913 static void
914 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
916 MonoThreadInfo *thread;
917 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
918 thread = mono_thread_info_current_unchecked ();
919 if (thread)
920 thread->jit_data = jit_tls;
922 mono_arch_cpu_init ();
925 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
927 static void
928 mono_thread_abort_dummy (MonoObject *obj)
930 if (mono_thread_attach_aborted_cb)
931 mono_thread_attach_aborted_cb (obj);
932 else
933 mono_thread_abort (obj);
936 static void
937 mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
939 MonoThreadInfo *thread;
940 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
941 thread = mono_thread_info_current_unchecked ();
942 if (thread)
943 thread->jit_data = jit_tls;
945 mono_arch_cpu_init ();
948 static void
949 mini_thread_cleanup (MonoNativeThreadId tid)
951 MonoJitTlsData *jit_tls = NULL;
952 MonoThreadInfo *info;
954 info = mono_thread_info_current_unchecked ();
956 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
957 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
958 * not a trivial thing.
960 * The current offender is mono_thread_manage which cleanup threads from the outside.
962 if (info && mono_thread_info_get_tid (info) == tid) {
963 jit_tls = (MonoJitTlsData *)info->jit_data;
964 info->jit_data = NULL;
966 mono_set_jit_tls (NULL);
968 /* If we attach a thread but never call into managed land, we might never get an lmf.*/
969 if (mono_get_lmf ()) {
970 mono_set_lmf (NULL);
971 mono_set_lmf_addr (NULL);
973 } else {
974 info = mono_thread_info_lookup (tid);
975 if (info) {
976 jit_tls = (MonoJitTlsData *)info->jit_data;
977 info->jit_data = NULL;
979 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
982 if (jit_tls)
983 free_jit_tls_data (jit_tls);
986 MonoJumpInfo *
987 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
989 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
991 ji->ip.i = ip;
992 ji->type = type;
993 ji->data.target = target;
994 ji->next = list;
996 return ji;
999 #if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
1001 static const char* const patch_info_str[] = {
1002 #define PATCH_INFO(a,b) "" #a,
1003 #include "patch-info.h"
1004 #undef PATCH_INFO
1007 const char*
1008 mono_ji_type_to_string (MonoJumpInfoType type)
1010 return patch_info_str [type];
1013 void
1014 mono_print_ji (const MonoJumpInfo *ji)
1016 switch (ji->type) {
1017 case MONO_PATCH_INFO_RGCTX_FETCH: {
1018 MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
1020 printf ("[RGCTX_FETCH ");
1021 mono_print_ji (entry->data);
1022 printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
1023 break;
1025 case MONO_PATCH_INFO_METHODCONST: {
1026 char *s = mono_method_full_name (ji->data.method, TRUE);
1027 printf ("[METHODCONST - %s]", s);
1028 g_free (s);
1029 break;
1031 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1032 printf ("[INTERNAL_METHOD - %s]", ji->data.name);
1033 break;
1035 default:
1036 printf ("[%s]", patch_info_str [ji->type]);
1037 break;
1041 #else
1043 const char*
1044 mono_ji_type_to_string (MonoJumpInfoType type)
1046 return "";
1049 void
1050 mono_print_ji (const MonoJumpInfo *ji)
1054 #endif
1057 * mono_patch_info_dup_mp:
1059 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
1061 MonoJumpInfo*
1062 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
1064 MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
1065 memcpy (res, patch_info, sizeof (MonoJumpInfo));
1067 switch (patch_info->type) {
1068 case MONO_PATCH_INFO_RVA:
1069 case MONO_PATCH_INFO_LDSTR:
1070 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1071 case MONO_PATCH_INFO_LDTOKEN:
1072 case MONO_PATCH_INFO_DECLSEC:
1073 res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
1074 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
1075 break;
1076 case MONO_PATCH_INFO_SWITCH:
1077 res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
1078 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
1079 res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1080 memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
1081 break;
1082 case MONO_PATCH_INFO_RGCTX_FETCH:
1083 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
1084 res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
1085 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
1086 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
1087 break;
1088 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1089 res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
1090 memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
1091 break;
1092 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1093 res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
1094 memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
1095 break;
1096 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
1097 MonoGSharedVtMethodInfo *info;
1098 MonoGSharedVtMethodInfo *oinfo;
1099 int i;
1101 oinfo = patch_info->data.gsharedvt_method;
1102 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
1103 res->data.gsharedvt_method = info;
1104 memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
1105 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
1106 for (i = 0; i < oinfo->num_entries; ++i) {
1107 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
1108 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1110 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
1112 //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
1113 //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
1114 break;
1116 case MONO_PATCH_INFO_VIRT_METHOD: {
1117 MonoJumpInfoVirtMethod *info;
1118 MonoJumpInfoVirtMethod *oinfo;
1120 oinfo = patch_info->data.virt_method;
1121 info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
1122 res->data.virt_method = info;
1123 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
1124 break;
1126 default:
1127 break;
1130 return res;
1133 guint
1134 mono_patch_info_hash (gconstpointer data)
1136 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
1138 switch (ji->type) {
1139 case MONO_PATCH_INFO_RVA:
1140 case MONO_PATCH_INFO_LDSTR:
1141 case MONO_PATCH_INFO_LDTOKEN:
1142 case MONO_PATCH_INFO_DECLSEC:
1143 return (ji->type << 8) | ji->data.token->token;
1144 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1145 return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
1146 case MONO_PATCH_INFO_INTERNAL_METHOD:
1147 return (ji->type << 8) | g_str_hash (ji->data.name);
1148 case MONO_PATCH_INFO_VTABLE:
1149 case MONO_PATCH_INFO_CLASS:
1150 case MONO_PATCH_INFO_IID:
1151 case MONO_PATCH_INFO_ADJUSTED_IID:
1152 case MONO_PATCH_INFO_METHODCONST:
1153 case MONO_PATCH_INFO_METHOD:
1154 case MONO_PATCH_INFO_METHOD_JUMP:
1155 case MONO_PATCH_INFO_IMAGE:
1156 case MONO_PATCH_INFO_ICALL_ADDR:
1157 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1158 case MONO_PATCH_INFO_FIELD:
1159 case MONO_PATCH_INFO_SFLDA:
1160 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1161 case MONO_PATCH_INFO_METHOD_RGCTX:
1162 case MONO_PATCH_INFO_SIGNATURE:
1163 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
1164 case MONO_PATCH_INFO_AOT_JIT_INFO:
1165 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1166 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1167 return (ji->type << 8) | (gssize)ji->data.target;
1168 case MONO_PATCH_INFO_GSHAREDVT_CALL:
1169 return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
1170 case MONO_PATCH_INFO_RGCTX_FETCH:
1171 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1172 MonoJumpInfoRgctxEntry *e = ji->data.rgctx_entry;
1174 return (ji->type << 8) | (gssize)e->method | (e->in_mrgctx) | e->info_type | mono_patch_info_hash (e->data);
1176 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1177 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
1178 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
1179 case MONO_PATCH_INFO_GC_NURSERY_START:
1180 case MONO_PATCH_INFO_GC_NURSERY_BITS:
1181 case MONO_PATCH_INFO_GOT_OFFSET:
1182 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1183 case MONO_PATCH_INFO_AOT_MODULE:
1184 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
1185 return (ji->type << 8);
1186 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1187 return (ji->type << 8) | (ji->data.index);
1188 case MONO_PATCH_INFO_SWITCH:
1189 return (ji->type << 8) | ji->data.table->table_size;
1190 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1191 return (ji->type << 8) | (gssize)ji->data.gsharedvt_method->method;
1192 case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
1193 /* Hash on the selector name */
1194 return g_str_hash (ji->data.target);
1195 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1196 return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->is_virtual;
1197 case MONO_PATCH_INFO_LDSTR_LIT:
1198 return g_str_hash (ji->data.target);
1199 case MONO_PATCH_INFO_VIRT_METHOD: {
1200 MonoJumpInfoVirtMethod *info = ji->data.virt_method;
1202 return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
1204 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1205 return (ji->type << 8) | g_str_hash (ji->data.target);
1206 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1207 return (ji->type << 8) | mono_signature_hash (ji->data.sig);
1208 default:
1209 printf ("info type: %d\n", ji->type);
1210 mono_print_ji (ji); printf ("\n");
1211 g_assert_not_reached ();
1212 return 0;
1217 * mono_patch_info_equal:
1219 * This might fail to recognize equivalent patches, i.e. floats, so its only
1220 * usable in those cases where this is not a problem, i.e. sharing GOT slots
1221 * in AOT.
1223 gint
1224 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
1226 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
1227 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
1229 if (ji1->type != ji2->type)
1230 return 0;
1232 switch (ji1->type) {
1233 case MONO_PATCH_INFO_RVA:
1234 case MONO_PATCH_INFO_LDSTR:
1235 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1236 case MONO_PATCH_INFO_LDTOKEN:
1237 case MONO_PATCH_INFO_DECLSEC:
1238 if ((ji1->data.token->image != ji2->data.token->image) ||
1239 (ji1->data.token->token != ji2->data.token->token) ||
1240 (ji1->data.token->has_context != ji2->data.token->has_context) ||
1241 (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) ||
1242 (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
1243 return 0;
1244 break;
1245 case MONO_PATCH_INFO_INTERNAL_METHOD:
1246 return g_str_equal (ji1->data.name, ji2->data.name);
1247 case MONO_PATCH_INFO_RGCTX_FETCH:
1248 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1249 MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
1250 MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
1252 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);
1254 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
1255 MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt;
1256 MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt;
1258 return c1->sig == c2->sig && c1->method == c2->method;
1260 case MONO_PATCH_INFO_GSHAREDVT_METHOD:
1261 return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
1262 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
1263 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;
1264 case MONO_PATCH_INFO_CASTCLASS_CACHE:
1265 return ji1->data.index == ji2->data.index;
1266 case MONO_PATCH_INFO_VIRT_METHOD:
1267 return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
1268 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
1269 if (ji1->data.target == ji2->data.target)
1270 return 1;
1271 return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
1272 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1273 return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
1274 default:
1275 if (ji1->data.target != ji2->data.target)
1276 return 0;
1277 break;
1280 return 1;
1283 gpointer
1284 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
1286 unsigned char *ip = patch_info->ip.i + code;
1287 gconstpointer target = NULL;
1289 error_init (error);
1291 switch (patch_info->type) {
1292 case MONO_PATCH_INFO_BB:
1294 * FIXME: This could be hit for methods without a prolog. Should use -1
1295 * but too much code depends on a 0 initial value.
1297 //g_assert (patch_info->data.bb->native_offset);
1298 target = patch_info->data.bb->native_offset + code;
1299 break;
1300 case MONO_PATCH_INFO_ABS:
1301 target = patch_info->data.target;
1302 break;
1303 case MONO_PATCH_INFO_LABEL:
1304 target = patch_info->data.inst->inst_c0 + code;
1305 break;
1306 case MONO_PATCH_INFO_IP:
1307 target = ip;
1308 break;
1309 case MONO_PATCH_INFO_METHOD_REL:
1310 target = code + patch_info->data.offset;
1311 break;
1312 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1313 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1314 if (!mi) {
1315 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
1316 g_assert_not_reached ();
1318 target = mono_icall_get_wrapper (mi);
1319 break;
1321 case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
1322 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
1323 if (!mi) {
1324 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
1325 g_assert_not_reached ();
1327 target = mi->func;
1328 break;
1330 case MONO_PATCH_INFO_METHOD_JUMP:
1331 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
1332 if (!mono_error_ok (error))
1333 return NULL;
1334 break;
1335 case MONO_PATCH_INFO_METHOD:
1336 if (patch_info->data.method == method) {
1337 target = code;
1338 } else {
1339 /* get the trampoline to the method from the domain */
1340 target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
1341 if (!mono_error_ok (error))
1342 return NULL;
1344 break;
1345 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
1346 gpointer code_slot;
1348 mono_domain_lock (domain);
1349 if (!domain_jit_info (domain)->method_code_hash)
1350 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
1351 code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
1352 if (!code_slot) {
1353 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
1354 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
1356 mono_domain_unlock (domain);
1357 target = code_slot;
1358 break;
1360 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
1361 #if defined(__native_client_codegen__)
1362 target = (gpointer)&__nacl_thread_suspension_needed;
1363 #else
1364 g_assert (mono_threads_is_coop_enabled ());
1365 target = (gpointer)&mono_polling_required;
1366 #endif
1367 break;
1368 case MONO_PATCH_INFO_SWITCH: {
1369 gpointer *jump_table;
1370 int i;
1371 #if defined(__native_client__) && defined(__native_client_codegen__)
1372 /* This memory will leak, but we don't care if we're */
1373 /* not deleting JIT'd methods anyway */
1374 jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
1375 #else
1376 if (method && method->dynamic) {
1377 jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
1378 } else {
1379 if (mono_aot_only) {
1380 jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1381 } else {
1382 jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
1385 #endif
1387 for (i = 0; i < patch_info->data.table->table_size; i++) {
1388 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
1391 target = jump_table;
1392 break;
1394 case MONO_PATCH_INFO_METHODCONST:
1395 case MONO_PATCH_INFO_CLASS:
1396 case MONO_PATCH_INFO_IMAGE:
1397 case MONO_PATCH_INFO_FIELD:
1398 case MONO_PATCH_INFO_SIGNATURE:
1399 case MONO_PATCH_INFO_AOT_MODULE:
1400 target = patch_info->data.target;
1401 break;
1402 case MONO_PATCH_INFO_IID:
1403 mono_class_init (patch_info->data.klass);
1404 target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
1405 break;
1406 case MONO_PATCH_INFO_ADJUSTED_IID:
1407 mono_class_init (patch_info->data.klass);
1408 target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
1409 break;
1410 case MONO_PATCH_INFO_VTABLE:
1411 target = mono_class_vtable (domain, patch_info->data.klass);
1412 g_assert (target);
1413 break;
1414 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
1415 MonoDelegateClassMethodPair *del_tramp = patch_info->data.del_tramp;
1417 if (del_tramp->is_virtual)
1418 target = mono_create_delegate_virtual_trampoline (domain, del_tramp->klass, del_tramp->method);
1419 else
1420 target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
1421 break;
1423 case MONO_PATCH_INFO_SFLDA: {
1424 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
1426 if (mono_class_field_is_special_static (patch_info->data.field)) {
1427 gpointer addr = NULL;
1429 mono_domain_lock (domain);
1430 if (domain->special_static_fields)
1431 addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
1432 mono_domain_unlock (domain);
1433 g_assert (addr);
1434 return addr;
1437 g_assert (vtable);
1438 if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
1439 /* Done by the generated code */
1441 else {
1442 if (run_cctors) {
1443 if (!mono_runtime_class_init_full (vtable, error)) {
1444 return NULL;
1448 target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
1449 break;
1451 case MONO_PATCH_INFO_RVA: {
1452 guint32 field_index = mono_metadata_token_index (patch_info->data.token->token);
1453 guint32 rva;
1455 mono_metadata_field_info (patch_info->data.token->image, field_index - 1, NULL, &rva, NULL);
1456 target = mono_image_rva_map (patch_info->data.token->image, rva);
1457 break;
1459 case MONO_PATCH_INFO_R4:
1460 case MONO_PATCH_INFO_R8:
1461 target = patch_info->data.target;
1462 break;
1463 case MONO_PATCH_INFO_EXC_NAME:
1464 target = patch_info->data.name;
1465 break;
1466 case MONO_PATCH_INFO_LDSTR:
1467 target =
1468 mono_ldstr_checked (domain, patch_info->data.token->image,
1469 mono_metadata_token_index (patch_info->data.token->token), error);
1470 break;
1471 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
1472 gpointer handle;
1473 MonoClass *handle_class;
1475 handle = mono_ldtoken_checked (patch_info->data.token->image,
1476 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1477 if (!mono_error_ok (error))
1478 return NULL;
1479 mono_class_init (handle_class);
1480 mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
1482 target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
1483 if (!mono_error_ok (error))
1484 return NULL;
1485 break;
1487 case MONO_PATCH_INFO_LDTOKEN: {
1488 gpointer handle;
1489 MonoClass *handle_class;
1491 handle = mono_ldtoken_checked (patch_info->data.token->image,
1492 patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
1493 if (!mono_error_ok (error))
1494 g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
1495 mono_class_init (handle_class);
1497 target = handle;
1498 break;
1500 case MONO_PATCH_INFO_DECLSEC:
1501 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
1502 break;
1503 case MONO_PATCH_INFO_ICALL_ADDR:
1504 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
1505 /* run_cctors == 0 -> AOT */
1506 if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1507 const char *exc_class;
1508 const char *exc_arg;
1510 if (run_cctors) {
1511 target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
1512 if (!target) {
1513 if (mono_aot_only) {
1514 mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
1515 return NULL;
1517 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));
1519 } else {
1520 target = NULL;
1522 } else {
1523 target = mono_lookup_internal_call (patch_info->data.method);
1525 if (!target && run_cctors)
1526 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
1528 break;
1529 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
1530 target = mono_thread_interruption_request_flag ();
1531 break;
1532 case MONO_PATCH_INFO_METHOD_RGCTX: {
1533 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
1534 g_assert (vtable);
1536 target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
1537 break;
1539 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
1540 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1542 target = GINT_TO_POINTER (MONO_RGCTX_SLOT_INDEX (slot));
1543 break;
1545 case MONO_PATCH_INFO_BB_OVF:
1546 case MONO_PATCH_INFO_EXC_OVF:
1547 case MONO_PATCH_INFO_GOT_OFFSET:
1548 case MONO_PATCH_INFO_NONE:
1549 break;
1550 case MONO_PATCH_INFO_RGCTX_FETCH: {
1551 int slot = mini_get_rgctx_entry_slot (patch_info->data.rgctx_entry);
1553 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
1554 break;
1556 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
1557 case MONO_PATCH_INFO_SEQ_POINT_INFO:
1558 if (!run_cctors)
1559 /* AOT, not needed */
1560 target = NULL;
1561 else
1562 target = mono_arch_get_seq_point_info (domain, code);
1563 break;
1564 #endif
1565 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
1566 int card_table_shift_bits;
1567 gpointer card_table_mask;
1569 target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
1570 break;
1572 case MONO_PATCH_INFO_GC_NURSERY_START: {
1573 int shift_bits;
1574 size_t size;
1576 target = mono_gc_get_nursery (&shift_bits, &size);
1577 break;
1579 case MONO_PATCH_INFO_GC_NURSERY_BITS: {
1580 int shift_bits;
1581 size_t size;
1583 mono_gc_get_nursery (&shift_bits, &size);
1585 target = (gpointer)(mgreg_t)shift_bits;
1586 break;
1588 case MONO_PATCH_INFO_CASTCLASS_CACHE: {
1589 target = mono_domain_alloc0 (domain, sizeof (gpointer));
1590 break;
1592 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
1593 target = NULL;
1594 break;
1596 case MONO_PATCH_INFO_LDSTR_LIT: {
1597 int len;
1598 char *s;
1600 len = strlen ((const char *)patch_info->data.target);
1601 s = (char *)mono_domain_alloc0 (domain, len + 1);
1602 memcpy (s, patch_info->data.target, len);
1603 target = s;
1605 break;
1607 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
1608 target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
1609 break;
1610 case MONO_PATCH_INFO_GET_TLS_TRAMP:
1611 target = mono_tls_get_tls_getter (patch_info->data.index, FALSE);
1612 break;
1613 case MONO_PATCH_INFO_SET_TLS_TRAMP:
1614 target = mono_tls_get_tls_setter (patch_info->data.index, FALSE);
1615 break;
1616 case MONO_PATCH_INFO_JIT_THREAD_ATTACH: {
1617 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_jit_thread_attach");
1618 g_assert (mi);
1619 target = mi->func;
1620 break;
1622 default:
1623 g_assert_not_reached ();
1626 return (gpointer)target;
1629 void
1630 mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
1632 MonoGenericInst *inst;
1633 int i;
1635 memset (gsctx, 0, sizeof (MonoGenericSharingContext));
1637 if (context && context->class_inst) {
1638 inst = context->class_inst;
1639 for (i = 0; i < inst->type_argc; ++i) {
1640 MonoType *type = inst->type_argv [i];
1642 if (mini_is_gsharedvt_gparam (type))
1643 gsctx->is_gsharedvt = TRUE;
1646 if (context && context->method_inst) {
1647 inst = context->method_inst;
1649 for (i = 0; i < inst->type_argc; ++i) {
1650 MonoType *type = inst->type_argv [i];
1652 if (mini_is_gsharedvt_gparam (type))
1653 gsctx->is_gsharedvt = TRUE;
1659 * LOCKING: Acquires the jit code hash lock.
1661 MonoJitInfo*
1662 mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
1664 MonoJitInfo *ji;
1665 static gboolean inited = FALSE;
1666 static int lookups = 0;
1667 static int failed_lookups = 0;
1669 mono_domain_jit_code_hash_lock (domain);
1670 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
1671 if (!ji && shared) {
1672 /* Try generic sharing */
1673 ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
1674 if (ji && !ji->has_generic_jit_info)
1675 ji = NULL;
1676 if (!inited) {
1677 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1678 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1679 inited = TRUE;
1682 ++lookups;
1683 if (!ji)
1684 ++failed_lookups;
1686 mono_domain_jit_code_hash_unlock (domain);
1688 return ji;
1691 static MonoJitInfo*
1692 lookup_method (MonoDomain *domain, MonoMethod *method)
1694 MonoJitInfo *ji;
1695 MonoMethod *shared;
1697 ji = mini_lookup_method (domain, method, NULL);
1699 if (!ji) {
1700 if (!mono_method_is_generic_sharable (method, FALSE))
1701 return NULL;
1702 shared = mini_get_shared_method (method);
1703 ji = mini_lookup_method (domain, method, shared);
1706 return ji;
1709 MonoJitInfo *
1710 mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
1712 return lookup_method (domain, method);
1715 #if ENABLE_JIT_MAP
1716 static FILE* perf_map_file;
1718 void
1719 mono_enable_jit_map (void)
1721 if (!perf_map_file) {
1722 char name [64];
1723 g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
1724 unlink (name);
1725 perf_map_file = fopen (name, "w");
1729 void
1730 mono_emit_jit_tramp (void *start, int size, const char *desc)
1732 if (perf_map_file)
1733 fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
1736 void
1737 mono_emit_jit_map (MonoJitInfo *jinfo)
1739 if (perf_map_file) {
1740 char *name = mono_method_full_name (jinfo_get_method (jinfo), TRUE);
1741 mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
1742 g_free (name);
1746 gboolean
1747 mono_jit_map_is_enabled (void)
1749 return perf_map_file != NULL;
1752 #endif
1754 static void
1755 no_gsharedvt_in_wrapper (void)
1757 g_assert_not_reached ();
1761 Overall algorithm:
1763 Limit JITing to mono_cpu_count
1764 This ensures there's always room for application progress and not just JITing.
1766 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.
1767 If the current thread is already JITing another method, don't wait as it might cause a deadlock.
1768 Dependency management in this case is too complex to justify implementing it.
1770 If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
1772 TODO:
1773 Get rid of cctor invocatio from within the JIT, it increases JIT duration and complicates things A LOT.
1774 Verify that we don't have too many spurious wakeups.
1775 Experiment with limiting to values around mono_cpu_count +/- 1 as this would enable progress during warmup.
1777 typedef struct {
1778 MonoMethod *method;
1779 MonoDomain *domain;
1780 int count;
1781 } JitCompilationEntry;
1783 typedef struct {
1784 GPtrArray *in_flight_methods; //JitCompilationEntry*
1785 int active_threads;
1786 int threads_waiting;
1787 MonoCoopMutex lock;
1788 MonoCoopCond cond;
1789 } JitCompilationData;
1791 static JitCompilationData compilation_data;
1792 static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
1794 static void
1795 mini_jit_init_job_control (void)
1797 mono_coop_mutex_init (&compilation_data.lock);
1798 mono_coop_cond_init (&compilation_data.cond);
1799 compilation_data.in_flight_methods = g_ptr_array_new ();
1802 static void
1803 lock_compilation_data (void)
1805 mono_coop_mutex_lock (&compilation_data.lock);
1806 fflush (stdout);
1809 static void
1810 unlock_compilation_data (void)
1812 fflush (stdout);
1813 mono_coop_mutex_unlock (&compilation_data.lock);
1816 static JitCompilationEntry*
1817 find_method (MonoMethod *method, MonoDomain *domain)
1819 int i;
1820 for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
1821 JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
1822 if (e->method == method && e->domain == domain)
1823 return e;
1826 return NULL;
1829 static void
1830 add_current_thread (MonoJitTlsData *jit_tls)
1832 if (jit_tls->active_jit_methods == 0)
1833 ++compilation_data.active_threads;
1834 ++jit_tls->active_jit_methods;
1837 //Returns true if this thread should wait
1838 static gboolean
1839 should_wait_for_available_cpu_capacity (void)
1841 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1843 //We can't suspend threads that are already JIT'ing something or we risk deadlocking
1844 if (jit_tls->active_jit_methods > 0)
1845 return FALSE;
1847 //If there are as many active threads as cores, JITing more will cause thrashing
1848 if (compilation_data.active_threads >= mono_cpu_count ()) {
1849 ++jit_methods_overload;
1850 return TRUE;
1852 return FALSE;
1856 * Returns true if this method waited successfully for another thread to JIT it
1858 static gboolean
1859 wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
1861 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1862 JitCompilationEntry *entry;
1865 static gboolean inited;
1866 if (!inited) {
1867 mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
1868 mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
1869 mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
1870 mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
1871 inited = TRUE;
1874 lock_compilation_data ();
1876 int waits = 0;
1877 while (should_wait_for_available_cpu_capacity ()) {
1878 fflush (stdout);
1879 ++compilation_data.threads_waiting;
1880 mono_coop_cond_wait (&compilation_data.cond, &compilation_data.lock);
1881 --compilation_data.threads_waiting;
1882 if (waits)
1883 ++jit_spurious_wakeups;
1884 ++waits;
1887 if (!(entry = find_method (method, domain))) {
1888 entry = g_new (JitCompilationEntry, 1);
1889 entry->method = method;
1890 entry->domain = domain;
1891 entry->count = 1;
1892 g_ptr_array_add (compilation_data.in_flight_methods, entry);
1893 add_current_thread (jit_tls);
1894 unlock_compilation_data ();
1895 return FALSE;
1896 } else if (jit_tls->active_jit_methods > 0) {
1897 //We can't suspend the current thread if it's already JITing a method.
1898 //Dependency management is too compilated and we want to get rid of this anyways.
1899 ++entry->count;
1900 ++jit_methods_multiple;
1901 unlock_compilation_data ();
1902 return FALSE;
1903 } else {
1904 ++jit_methods_waited;
1905 while (TRUE) {
1906 fflush (stdout);
1907 ++compilation_data.threads_waiting;
1908 mono_coop_cond_wait (&compilation_data.cond, &compilation_data.lock);
1909 --compilation_data.threads_waiting;
1911 if (!find_method (method, domain)) {
1912 unlock_compilation_data ();
1913 return TRUE;
1914 } else {
1915 ++jit_spurious_wakeups;
1921 static void
1922 unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
1924 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1926 lock_compilation_data ();
1928 --jit_tls->active_jit_methods;
1929 if (jit_tls->active_jit_methods == 0)
1930 --compilation_data.active_threads;
1932 JitCompilationEntry *entry = find_method (method, target_domain);
1933 g_assert (entry); // It would be weird to fail
1934 if (--entry->count == 0) {
1935 g_ptr_array_remove (compilation_data.in_flight_methods, entry);
1936 g_free (entry);
1939 if (compilation_data.threads_waiting)
1940 mono_coop_cond_broadcast (&compilation_data.cond);
1941 unlock_compilation_data ();
1945 static gpointer
1946 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
1948 MonoDomain *target_domain, *domain = mono_domain_get ();
1949 MonoJitInfo *info;
1950 gpointer code = NULL, p;
1951 MonoJitInfo *ji;
1952 MonoJitICallInfo *callinfo = NULL;
1953 WrapperInfo *winfo = NULL;
1955 error_init (error);
1957 #ifdef ENABLE_INTERPRETER
1958 if (mono_use_interpreter && !jit_only) {
1959 code = mono_interp_create_method_pointer (method, error);
1960 if (code)
1961 return code;
1963 #endif
1965 if (mono_llvm_only)
1966 /* Should be handled by the caller */
1967 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
1970 * ICALL wrappers are handled specially, since there is only one copy of them
1971 * shared by all appdomains.
1973 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1974 winfo = mono_marshal_get_wrapper_info (method);
1975 if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
1976 callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func);
1977 g_assert (callinfo);
1979 /* Must be domain neutral since there is only one copy */
1980 opt |= MONO_OPT_SHARED;
1981 } else {
1982 /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
1983 opt &= ~MONO_OPT_SHARED;
1986 if (opt & MONO_OPT_SHARED)
1987 target_domain = mono_get_root_domain ();
1988 else
1989 target_domain = domain;
1991 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
1992 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
1994 g_assert (info);
1995 if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
1996 MonoGenericContext *ctx = NULL;
1997 if (method->is_inflated)
1998 ctx = mono_method_get_context (method);
1999 method = info->d.synchronized_inner.method;
2000 if (ctx) {
2001 method = mono_class_inflate_generic_method_checked (method, ctx, error);
2002 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
2007 lookup_start:
2008 info = lookup_method (target_domain, method);
2009 if (info) {
2010 /* We can't use a domain specific method in another domain */
2011 if (! ((domain != target_domain) && !info->domain_neutral)) {
2012 MonoVTable *vtable;
2014 mono_jit_stats.methods_lookups++;
2015 vtable = mono_class_vtable_full (domain, method->klass, error);
2016 if (!is_ok (error))
2017 return NULL;
2018 g_assert (vtable);
2019 if (!mono_runtime_class_init_full (vtable, error))
2020 return NULL;
2021 return mono_create_ftnptr (target_domain, info->code_start);
2025 #ifdef MONO_USE_AOT_COMPILER
2026 if (opt & MONO_OPT_AOT) {
2027 MonoDomain *domain = mono_domain_get ();
2029 mono_class_init (method->klass);
2031 if ((code = mono_aot_get_method_checked (domain, method, error))) {
2032 MonoVTable *vtable;
2034 if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
2036 * The suspend code needs to be able to lookup these methods by ip in async context,
2037 * so preload their jit info.
2039 MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
2040 g_assert (ji);
2044 * In llvm-only mode, method might be a shared method, so we can't initialize its class.
2045 * This is not a problem, since it will be initialized when the method is first
2046 * called by init_method ().
2048 if (!mono_llvm_only) {
2049 vtable = mono_class_vtable (domain, method->klass);
2050 g_assert (vtable);
2051 if (!mono_runtime_class_init_full (vtable, error))
2052 return NULL;
2055 if (!is_ok (error))
2056 return NULL;
2058 #endif
2060 if (!code && mono_llvm_only) {
2061 if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
2062 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2064 if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
2066 * These wrappers are only created for signatures which are in the program, but
2067 * sometimes we load methods too eagerly and have to create them even if they
2068 * will never be called.
2070 return no_gsharedvt_in_wrapper;
2075 if (!code) {
2076 if (wait_or_register_method_to_compile (method, target_domain))
2077 goto lookup_start;
2078 code = mono_jit_compile_method_inner (method, target_domain, opt, error);
2079 unregister_method_for_compile (method, target_domain);
2081 if (!mono_error_ok (error))
2082 return NULL;
2084 if (!code && mono_llvm_only) {
2085 printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
2086 g_assert_not_reached ();
2089 if (!code)
2090 return NULL;
2092 if (method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER || method->wrapper_type == MONO_WRAPPER_ALLOC) {
2093 MonoDomain *d;
2096 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
2098 ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
2099 g_assert (ji);
2102 p = mono_create_ftnptr (target_domain, code);
2104 if (callinfo) {
2105 /*mono_register_jit_icall_wrapper takes the loader lock, so we take it on the outside. */
2106 mono_loader_lock ();
2107 mono_jit_lock ();
2108 if (!callinfo->wrapper) {
2109 callinfo->wrapper = p;
2110 mono_register_jit_icall_wrapper (callinfo, p);
2112 mono_jit_unlock ();
2113 mono_loader_unlock ();
2116 return p;
2119 gpointer
2120 mono_jit_compile_method (MonoMethod *method, MonoError *error)
2122 gpointer code;
2124 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
2125 return code;
2129 * mono_jit_compile_method_jit_only:
2131 * Compile METHOD using the JIT/AOT, even in interpreted mode.
2133 gpointer
2134 mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
2136 gpointer code;
2138 code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
2139 return code;
2142 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2143 static void
2144 invalidated_delegate_trampoline (char *desc)
2146 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
2147 "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.",
2148 desc);
2150 #endif
2153 * mono_jit_free_method:
2155 * Free all memory allocated by the JIT for METHOD.
2157 static void
2158 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
2160 MonoJitDynamicMethodInfo *ji;
2161 gboolean destroy = TRUE;
2162 GHashTableIter iter;
2163 MonoJumpList *jlist;
2165 g_assert (method->dynamic);
2167 mono_domain_lock (domain);
2168 ji = mono_dynamic_code_hash_lookup (domain, method);
2169 mono_domain_unlock (domain);
2171 if (!ji)
2172 return;
2174 mono_debug_remove_method (method, domain);
2175 mono_lldb_remove_method (domain, method, ji);
2177 mono_domain_lock (domain);
2178 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
2179 mono_domain_jit_code_hash_lock (domain);
2180 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
2181 mono_domain_jit_code_hash_unlock (domain);
2182 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
2184 /* requires the domain lock - took above */
2185 mono_conc_hashtable_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
2187 /* Remove jump targets in this method */
2188 g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
2189 while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
2190 GSList *tmp, *remove;
2192 remove = NULL;
2193 for (tmp = jlist->list; tmp; tmp = tmp->next) {
2194 guint8 *ip = (guint8 *)tmp->data;
2196 if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
2197 remove = g_slist_prepend (remove, tmp);
2199 for (tmp = remove; tmp; tmp = tmp->next) {
2200 jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
2202 g_slist_free (remove);
2204 mono_domain_unlock (domain);
2206 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
2207 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2209 * Instead of freeing the code, change it to call an error routine
2210 * so people can fix their code.
2212 char *type = mono_type_full_name (&method->klass->byval_arg);
2213 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
2215 g_free (type);
2216 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
2217 destroy = FALSE;
2219 #endif
2222 * This needs to be done before freeing code_mp, since the code address is the
2223 * key in the table, so if we free the code_mp first, another thread can grab the
2224 * same code address and replace our entry in the table.
2226 mono_jit_info_table_remove (domain, ji->ji);
2228 if (destroy)
2229 mono_code_manager_destroy (ji->code_mp);
2230 g_free (ji);
2233 gpointer
2234 mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
2236 MonoDomain *target_domain;
2237 MonoJitInfo *info;
2239 if (default_opt & MONO_OPT_SHARED)
2240 target_domain = mono_get_root_domain ();
2241 else
2242 target_domain = domain;
2244 info = lookup_method (target_domain, method);
2245 if (info) {
2246 /* We can't use a domain specific method in another domain */
2247 if (! ((domain != target_domain) && !info->domain_neutral)) {
2248 mono_jit_stats.methods_lookups++;
2249 if (ji)
2250 *ji = info;
2251 return info->code_start;
2255 if (ji)
2256 *ji = NULL;
2257 return NULL;
2260 static guint32 bisect_opt = 0;
2261 static GHashTable *bisect_methods_hash = NULL;
2263 void
2264 mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
2266 FILE *file;
2267 char method_name [2048];
2269 bisect_opt = opt;
2270 bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
2271 g_assert (bisect_methods_hash);
2273 file = fopen (method_list_filename, "r");
2274 g_assert (file);
2276 while (fgets (method_name, sizeof (method_name), file)) {
2277 size_t len = strlen (method_name);
2278 g_assert (len > 0);
2279 g_assert (method_name [len - 1] == '\n');
2280 method_name [len - 1] = 0;
2281 g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
2283 g_assert (feof (file));
2286 gboolean mono_do_single_method_regression = FALSE;
2287 guint32 mono_single_method_regression_opt = 0;
2288 MonoMethod *mono_current_single_method;
2289 GSList *mono_single_method_list;
2290 GHashTable *mono_single_method_hash;
2292 guint32
2293 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
2295 g_assert (method);
2297 if (bisect_methods_hash) {
2298 char *name = mono_method_full_name (method, TRUE);
2299 void *res = g_hash_table_lookup (bisect_methods_hash, name);
2300 g_free (name);
2301 if (res)
2302 return default_opt | bisect_opt;
2304 if (!mono_do_single_method_regression)
2305 return default_opt;
2306 if (!mono_current_single_method) {
2307 if (!mono_single_method_hash)
2308 mono_single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
2309 if (!g_hash_table_lookup (mono_single_method_hash, method)) {
2310 g_hash_table_insert (mono_single_method_hash, method, method);
2311 mono_single_method_list = g_slist_prepend (mono_single_method_list, method);
2313 return default_opt;
2315 if (method == mono_current_single_method)
2316 return mono_single_method_regression_opt;
2317 return default_opt;
2320 gpointer
2321 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
2323 return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
2326 typedef struct {
2327 MonoMethod *method;
2328 gpointer compiled_method;
2329 gpointer runtime_invoke;
2330 MonoVTable *vtable;
2331 MonoDynCallInfo *dyn_call_info;
2332 MonoClass *ret_box_class;
2333 MonoMethodSignature *sig;
2334 gboolean gsharedvt_invoke;
2335 gpointer *wrapper_arg;
2336 } RuntimeInvokeInfo;
2338 static RuntimeInvokeInfo*
2339 create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
2341 MonoMethod *invoke;
2342 RuntimeInvokeInfo *info;
2344 info = g_new0 (RuntimeInvokeInfo, 1);
2345 info->compiled_method = compiled_method;
2346 if (mono_llvm_only && method->string_ctor)
2347 info->sig = mono_marshal_get_string_ctor_signature (method);
2348 else
2349 info->sig = mono_method_signature (method);
2351 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
2352 info->vtable = mono_class_vtable_full (domain, method->klass, error);
2353 if (!mono_error_ok (error))
2354 return NULL;
2355 g_assert (info->vtable);
2357 MonoMethodSignature *sig = info->sig;
2358 MonoType *ret_type;
2361 * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
2362 * in full-aot mode, so we use a slower, but more generic wrapper if
2363 * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
2365 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2366 if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
2367 gboolean supported = TRUE;
2368 int i;
2370 if (method->string_ctor)
2371 sig = mono_marshal_get_string_ctor_signature (method);
2373 for (i = 0; i < sig->param_count; ++i) {
2374 MonoType *t = sig->params [i];
2376 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
2377 supported = FALSE;
2380 if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
2381 supported = FALSE;
2383 if (supported)
2384 info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
2386 #endif
2388 ret_type = sig->ret;
2389 switch (ret_type->type) {
2390 case MONO_TYPE_VOID:
2391 break;
2392 case MONO_TYPE_I1:
2393 case MONO_TYPE_U1:
2394 case MONO_TYPE_I2:
2395 case MONO_TYPE_U2:
2396 case MONO_TYPE_I4:
2397 case MONO_TYPE_U4:
2398 case MONO_TYPE_I:
2399 case MONO_TYPE_U:
2400 case MONO_TYPE_I8:
2401 case MONO_TYPE_U8:
2402 case MONO_TYPE_BOOLEAN:
2403 case MONO_TYPE_CHAR:
2404 case MONO_TYPE_R4:
2405 case MONO_TYPE_R8:
2406 info->ret_box_class = mono_class_from_mono_type (ret_type);
2407 break;
2408 case MONO_TYPE_PTR:
2409 info->ret_box_class = mono_defaults.int_class;
2410 break;
2411 case MONO_TYPE_STRING:
2412 case MONO_TYPE_CLASS:
2413 case MONO_TYPE_ARRAY:
2414 case MONO_TYPE_SZARRAY:
2415 case MONO_TYPE_OBJECT:
2416 break;
2417 case MONO_TYPE_GENERICINST:
2418 if (!MONO_TYPE_IS_REFERENCE (ret_type))
2419 info->ret_box_class = mono_class_from_mono_type (ret_type);
2420 break;
2421 case MONO_TYPE_VALUETYPE:
2422 info->ret_box_class = mono_class_from_mono_type (ret_type);
2423 break;
2424 default:
2425 g_assert_not_reached ();
2426 break;
2429 if (!info->dyn_call_info) {
2430 if (mono_llvm_only) {
2431 #ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
2432 g_assert_not_reached ();
2433 #endif
2434 info->gsharedvt_invoke = TRUE;
2435 if (!callee_gsharedvt) {
2436 /* Invoke a gsharedvt out wrapper instead */
2437 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2438 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2440 info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
2441 info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
2443 /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
2444 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2445 g_free (wrapper_sig);
2447 info->compiled_method = mono_jit_compile_method (wrapper, error);
2448 if (!mono_error_ok (error)) {
2449 g_free (info);
2450 return NULL;
2452 } else {
2453 /* Gsharedvt methods can be invoked the same way */
2454 /* The out wrapper has the same signature as the compiled gsharedvt method */
2455 MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
2457 info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
2459 invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
2460 g_free (wrapper_sig);
2463 info->runtime_invoke = mono_jit_compile_method (invoke, error);
2464 if (!mono_error_ok (error)) {
2465 g_free (info);
2466 return NULL;
2470 return info;
2473 static MonoObject*
2474 mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
2476 MonoMethodSignature *sig = info->sig;
2477 MonoDomain *domain = mono_domain_get ();
2478 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2479 gpointer *args;
2480 gpointer retval_ptr;
2481 guint8 retval [256];
2482 gpointer *param_refs;
2483 int i, pindex;
2485 error_init (error);
2487 g_assert (info->gsharedvt_invoke);
2490 * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
2491 * The advantage of this is the gsharedvt out wrappers have a reduced set of
2492 * signatures, so we only have to generate runtime invoke wrappers for these
2493 * signatures.
2494 * This code also handles invocation of gsharedvt methods directly, no
2495 * out wrappers are used in that case.
2497 args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2498 param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
2499 pindex = 0;
2501 * The runtime invoke wrappers expects pointers to primitive types, so have to
2502 * use indirections.
2504 if (sig->hasthis)
2505 args [pindex ++] = &obj;
2506 if (sig->ret->type != MONO_TYPE_VOID) {
2507 retval_ptr = (gpointer)&retval;
2508 args [pindex ++] = &retval_ptr;
2510 for (i = 0; i < sig->param_count; ++i) {
2511 MonoType *t = sig->params [i];
2513 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
2514 MonoClass *klass = mono_class_from_mono_type (t);
2515 guint8 *nullable_buf;
2516 int size;
2518 size = mono_class_value_size (klass, NULL);
2519 nullable_buf = g_alloca (size);
2520 g_assert (nullable_buf);
2522 /* The argument pointed to by params [i] is either a boxed vtype or null */
2523 mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
2524 params [i] = nullable_buf;
2527 if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
2528 param_refs [i] = params [i];
2529 params [i] = &(param_refs [i]);
2531 args [pindex ++] = &params [i];
2533 /* The gsharedvt out wrapper has an extra argument which contains the method to call */
2534 args [pindex ++] = &info->wrapper_arg;
2536 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2538 runtime_invoke (NULL, args, exc, info->compiled_method);
2539 if (exc && *exc)
2540 return NULL;
2542 if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
2543 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2544 else
2545 return *(MonoObject**)retval;
2549 * mono_jit_runtime_invoke:
2550 * \param method: the method to invoke
2551 * \param obj: this pointer
2552 * \param params: array of parameter values.
2553 * \param exc: Set to the exception raised in the managed method.
2554 * \param error: error or caught exception object
2555 * If \p exc is NULL, \p error is thrown instead.
2556 * If coop is enabled, \p exc argument is ignored -
2557 * all exceptions are caught and propagated through \p error
2559 static MonoObject*
2560 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2562 MonoMethod *invoke, *callee;
2563 MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
2564 MonoDomain *domain = mono_domain_get ();
2565 MonoJitDomainInfo *domain_info;
2566 RuntimeInvokeInfo *info, *info2;
2567 MonoJitInfo *ji = NULL;
2568 gboolean callee_gsharedvt = FALSE;
2570 #ifdef ENABLE_INTERPRETER
2571 if (mono_use_interpreter)
2572 return mono_interp_runtime_invoke (method, obj, params, exc, error);
2573 #endif
2575 error_init (error);
2577 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
2578 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
2579 return NULL;
2582 domain_info = domain_jit_info (domain);
2584 info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
2586 if (!info) {
2587 if (mono_security_core_clr_enabled ()) {
2589 * This might be redundant since mono_class_vtable () already does this,
2590 * but keep it just in case for moonlight.
2592 mono_class_setup_vtable (method->klass);
2593 if (mono_class_has_failure (method->klass)) {
2594 mono_error_set_for_class_failure (error, method->klass);
2595 if (exc)
2596 *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
2597 return NULL;
2601 gpointer compiled_method;
2603 callee = method;
2604 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
2605 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
2607 * Array Get/Set/Address methods. The JIT implements them using inline code
2608 * inside the runtime invoke wrappers, so no need to compile them.
2610 if (mono_aot_only) {
2612 * Call a wrapper, since the runtime invoke wrapper was not generated.
2614 MonoMethod *wrapper;
2616 wrapper = mono_marshal_get_array_accessor_wrapper (method);
2617 invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
2618 callee = wrapper;
2619 } else {
2620 callee = NULL;
2624 if (callee) {
2625 compiled_method = mono_jit_compile_method (callee, error);
2626 if (!compiled_method) {
2627 g_assert (!mono_error_ok (error));
2628 return NULL;
2631 if (mono_llvm_only) {
2632 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
2633 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2634 if (callee_gsharedvt)
2635 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
2638 if (!callee_gsharedvt)
2639 compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
2640 } else {
2641 compiled_method = NULL;
2644 info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
2645 if (!mono_error_ok (error))
2646 return NULL;
2648 mono_domain_lock (domain);
2649 info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
2650 mono_domain_unlock (domain);
2651 if (info2) {
2652 g_free (info);
2653 info = info2;
2658 * We need this here because mono_marshal_get_runtime_invoke can place
2659 * the helper method in System.Object and not the target class.
2661 if (!mono_runtime_class_init_full (info->vtable, error)) {
2662 if (exc)
2663 *exc = (MonoObject*) mono_error_convert_to_exception (error);
2664 return NULL;
2667 /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
2668 we always catch the exception and propagate it through the MonoError */
2669 gboolean catchExcInMonoError =
2670 (exc == NULL) && mono_threads_is_coop_enabled ();
2671 MonoObject *invoke_exc = NULL;
2672 if (catchExcInMonoError)
2673 exc = &invoke_exc;
2675 /* The wrappers expect this to be initialized to NULL */
2676 if (exc)
2677 *exc = NULL;
2679 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
2680 if (info->dyn_call_info) {
2681 MonoMethodSignature *sig = mono_method_signature (method);
2682 gpointer *args;
2683 static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
2684 int i, pindex;
2685 guint8 buf [512];
2686 guint8 retval [256];
2688 if (!dyn_runtime_invoke) {
2689 invoke = mono_marshal_get_runtime_invoke_dynamic ();
2690 dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
2691 if (!mono_error_ok (error))
2692 return NULL;
2695 /* Convert the arguments to the format expected by start_dyn_call () */
2696 args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
2697 pindex = 0;
2698 if (sig->hasthis)
2699 args [pindex ++] = &obj;
2700 for (i = 0; i < sig->param_count; ++i) {
2701 MonoType *t = sig->params [i];
2703 if (t->byref) {
2704 args [pindex ++] = &params [i];
2705 } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
2706 args [pindex ++] = &params [i];
2707 } else {
2708 args [pindex ++] = params [i];
2712 //printf ("M: %s\n", mono_method_full_name (method, TRUE));
2714 mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
2716 dyn_runtime_invoke (buf, exc, info->compiled_method);
2717 mono_arch_finish_dyn_call (info->dyn_call_info, buf);
2719 if (catchExcInMonoError && *exc != NULL) {
2720 mono_error_set_exception_instance (error, (MonoException*) *exc);
2721 return NULL;
2724 if (info->ret_box_class)
2725 return mono_value_box_checked (domain, info->ret_box_class, retval, error);
2726 else
2727 return *(MonoObject**)retval;
2729 #endif
2731 MonoObject *result;
2733 if (mono_llvm_only) {
2734 result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
2735 if (!is_ok (error))
2736 return NULL;
2737 } else {
2738 runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
2740 result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
2742 if (catchExcInMonoError && *exc != NULL)
2743 mono_error_set_exception_instance (error, (MonoException*) *exc);
2744 return result;
2747 typedef struct {
2748 MonoVTable *vtable;
2749 int slot;
2750 } IMTTrampInfo;
2752 typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
2755 * mini_llvmonly_initial_imt_tramp:
2757 * This function is called the first time a call is made through an IMT trampoline.
2758 * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
2760 static gpointer
2761 mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2763 IMTTrampInfo *info = (IMTTrampInfo*)arg;
2764 gpointer *imt;
2765 gpointer *ftndesc;
2766 IMTTrampFunc func;
2768 mono_vtable_build_imt_slot (info->vtable, info->slot);
2770 imt = (gpointer*)info->vtable;
2771 imt -= MONO_IMT_SIZE;
2773 /* Return what the real IMT trampoline returns */
2774 ftndesc = imt [info->slot];
2775 func = ftndesc [0];
2777 if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
2778 /* Happens when the imt slot contains only a generic virtual method */
2779 return NULL;
2780 return func ((gpointer *)ftndesc [1], imt_method);
2783 /* This is called indirectly through an imt slot. */
2784 static gpointer
2785 mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2787 int i = 0;
2789 /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
2790 while (arg [i] && arg [i] != imt_method)
2791 i += 2;
2792 g_assert (arg [i]);
2794 return arg [i + 1];
2797 /* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
2798 static gpointer
2799 mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
2801 //g_assert (arg [0] == imt_method);
2802 return arg [1];
2805 static gpointer
2806 mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
2808 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
2809 if (arg [0] == imt_method)
2810 return arg [1];
2811 else
2812 return arg [3];
2815 static gpointer
2816 mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
2818 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
2819 if (arg [0] == imt_method)
2820 return arg [1];
2821 else if (arg [2] == imt_method)
2822 return arg [3];
2823 else
2824 return arg [5];
2828 * A version of the imt trampoline used for generic virtual/variant iface methods.
2829 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
2830 * in the search table. The original JIT code had a 'fallback' trampoline it could
2831 * call, but we can't do that, so we just return NULL, and the compiled code
2832 * will handle it.
2834 static gpointer
2835 mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
2837 int i = 0;
2839 while (arg [i] && arg [i] != imt_method)
2840 i += 2;
2841 if (!arg [i])
2842 return NULL;
2844 return arg [i + 1];
2847 static gpointer
2848 mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
2850 gpointer *buf;
2851 gpointer *res;
2852 int i, index, real_count;
2853 gboolean virtual_generic = FALSE;
2856 * Create an array which is passed to the imt trampoline functions.
2857 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
2860 real_count = 0;
2861 for (i = 0; i < count; ++i) {
2862 MonoIMTCheckItem *item = imt_entries [i];
2864 if (item->is_equals)
2865 real_count ++;
2866 if (item->has_target_code)
2867 virtual_generic = TRUE;
2871 * Initialize all vtable entries reachable from this imt slot, so the compiled
2872 * code doesn't have to check it.
2874 for (i = 0; i < count; ++i) {
2875 MonoIMTCheckItem *item = imt_entries [i];
2876 int vt_slot;
2878 if (!item->is_equals || item->has_target_code)
2879 continue;
2880 vt_slot = item->value.vtable_slot;
2881 mono_init_vtable_slot (vtable, vt_slot);
2884 /* Save the entries into an array */
2885 buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
2886 index = 0;
2887 for (i = 0; i < count; ++i) {
2888 MonoIMTCheckItem *item = imt_entries [i];
2890 if (!item->is_equals)
2891 continue;
2893 g_assert (item->key);
2894 buf [(index * 2)] = item->key;
2895 if (item->has_target_code)
2896 buf [(index * 2) + 1] = item->value.target_code;
2897 else
2898 buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
2899 index ++;
2901 buf [(index * 2)] = NULL;
2902 buf [(index * 2) + 1] = fail_tramp;
2905 * Return a function descriptor for a C function with 'buf' as its argument.
2906 * It will by called by JITted code.
2908 res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
2909 switch (real_count) {
2910 case 1:
2911 res [0] = mono_llvmonly_imt_tramp_1;
2912 break;
2913 case 2:
2914 res [0] = mono_llvmonly_imt_tramp_2;
2915 break;
2916 case 3:
2917 res [0] = mono_llvmonly_imt_tramp_3;
2918 break;
2919 default:
2920 res [0] = mono_llvmonly_imt_tramp;
2921 break;
2923 if (virtual_generic || fail_tramp)
2924 res [0] = mono_llvmonly_fallback_imt_tramp;
2925 res [1] = buf;
2927 return res;
2930 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
2932 MonoException *exc = NULL;
2933 MonoJitInfo *ji;
2934 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2935 MONO_SIG_HANDLER_GET_CONTEXT;
2937 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
2939 MONO_ENTER_GC_UNSAFE_UNBALANCED;
2941 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
2942 if (mono_arch_is_int_overflow (ctx, info))
2944 * The spec says this throws ArithmeticException, but MS throws the derived
2945 * OverflowException.
2947 exc = mono_get_exception_overflow ();
2948 else
2949 exc = mono_get_exception_divide_by_zero ();
2950 #else
2951 exc = mono_get_exception_divide_by_zero ();
2952 #endif
2954 if (!ji) {
2955 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
2956 goto exit;
2958 mono_handle_native_crash ("SIGFPE", ctx, info);
2959 if (mono_do_crash_chaining) {
2960 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
2961 goto exit;
2965 mono_arch_handle_exception (ctx, exc);
2967 exit:
2968 MONO_EXIT_GC_UNSAFE_UNBALANCED;
2971 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
2973 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
2974 MONO_SIG_HANDLER_GET_CONTEXT;
2976 if (mono_runtime_get_no_exec ())
2977 exit (1);
2980 mono_handle_native_crash ("SIGILL", ctx, info);
2981 if (mono_do_crash_chaining) {
2982 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
2983 return;
2986 g_assert_not_reached ();
2989 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
2990 #define HAVE_SIG_INFO
2991 #endif
2993 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
2995 MonoJitInfo *ji;
2996 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2997 gpointer fault_addr = NULL;
2998 #ifdef HAVE_SIG_INFO
2999 MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
3000 #else
3001 void *info = NULL;
3002 #endif
3003 MONO_SIG_HANDLER_GET_CONTEXT;
3005 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
3006 if (mono_arch_is_single_step_event (info, ctx)) {
3007 mono_debugger_agent_single_step_event (ctx);
3008 return;
3009 } else if (mono_arch_is_breakpoint_event (info, ctx)) {
3010 mono_debugger_agent_breakpoint_hit (ctx);
3011 return;
3013 #endif
3015 #if defined(HAVE_SIG_INFO)
3016 #if !defined(HOST_WIN32)
3017 fault_addr = info->si_addr;
3018 if (mono_aot_is_pagefault (info->si_addr)) {
3019 mono_aot_handle_pagefault (info->si_addr);
3020 return;
3022 #endif
3024 /* The thread might no be registered with the runtime */
3025 if (!mono_domain_get () || !jit_tls) {
3026 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3027 return;
3028 mono_handle_native_crash ("SIGSEGV", ctx, info);
3029 if (mono_do_crash_chaining) {
3030 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3031 return;
3034 #endif
3036 ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
3038 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3039 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
3040 return;
3042 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3043 /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
3044 fault_addr = info->si_addr;
3045 if (fault_addr == NULL) {
3046 MonoContext mctx;
3048 mono_sigctx_to_monoctx (ctx, &mctx);
3050 fault_addr = MONO_CONTEXT_GET_SP (&mctx);
3052 #endif
3054 if (jit_tls->stack_size &&
3055 ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
3057 * The hard-guard page has been hit: there is not much we can do anymore
3058 * Print a hopefully clear message and abort.
3060 mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
3061 g_assert_not_reached ();
3062 } else {
3063 /* The original handler might not like that it is executed on an altstack... */
3064 if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3065 return;
3067 mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
3069 #else
3071 if (!ji) {
3072 if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
3073 return;
3075 mono_handle_native_crash ("SIGSEGV", ctx, info);
3077 if (mono_do_crash_chaining) {
3078 mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
3079 return;
3083 mono_arch_handle_exception (ctx, NULL);
3084 #endif
3087 MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
3089 MonoException *exc;
3090 MONO_SIG_HANDLER_GET_CONTEXT;
3092 MONO_ENTER_GC_UNSAFE_UNBALANCED;
3094 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
3096 mono_arch_handle_exception (ctx, exc);
3098 MONO_EXIT_GC_UNSAFE_UNBALANCED;
3101 #ifndef DISABLE_REMOTING
3102 /* mono_jit_create_remoting_trampoline:
3103 * @method: pointer to the method info
3105 * Creates a trampoline which calls the remoting functions. This
3106 * is used in the vtable of transparent proxies.
3108 * Returns: a pointer to the newly created code
3110 static gpointer
3111 mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
3113 MonoMethod *nm;
3114 guint8 *addr = NULL;
3116 error_init (error);
3118 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
3119 return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
3120 domain, NULL);
3123 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
3124 (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
3125 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
3126 else
3127 nm = method;
3128 addr = (guint8 *)mono_compile_method_checked (nm, error);
3129 return_val_if_nok (error, NULL);
3130 return mono_get_addr_from_ftnptr (addr);
3132 #endif
3134 static G_GNUC_UNUSED void
3135 no_imt_trampoline (void)
3137 g_assert_not_reached ();
3140 static G_GNUC_UNUSED void
3141 no_vcall_trampoline (void)
3143 g_assert_not_reached ();
3146 static gpointer *vtable_trampolines;
3147 static int vtable_trampolines_size;
3149 gpointer
3150 mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
3152 int index = slot_index + MONO_IMT_SIZE;
3154 if (mono_llvm_only) {
3155 if (slot_index < 0) {
3156 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
3157 // FIXME: Memory management
3158 gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
3159 IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
3160 info->vtable = vt;
3161 info->slot = index;
3162 ftndesc [0] = mini_llvmonly_initial_imt_tramp;
3163 ftndesc [1] = info;
3164 mono_memory_barrier ();
3165 return ftndesc;
3166 } else {
3167 return NULL;
3171 g_assert (slot_index >= - MONO_IMT_SIZE);
3172 if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
3173 mono_jit_lock ();
3174 if (!vtable_trampolines || index >= vtable_trampolines_size) {
3175 int new_size;
3176 gpointer new_table;
3178 new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
3179 while (new_size <= index)
3180 new_size *= 2;
3181 new_table = g_new0 (gpointer, new_size);
3183 if (vtable_trampolines)
3184 memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
3185 g_free (vtable_trampolines);
3186 mono_memory_barrier ();
3187 vtable_trampolines = (void **)new_table;
3188 vtable_trampolines_size = new_size;
3190 mono_jit_unlock ();
3193 if (!vtable_trampolines [index])
3194 vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
3195 return vtable_trampolines [index];
3198 static gpointer
3199 mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
3201 return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
3204 static gboolean
3205 mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
3207 if (mono_llvm_only)
3208 return FALSE;
3210 gpointer *imt = (gpointer*)vt;
3211 imt -= MONO_IMT_SIZE;
3213 return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
3216 static gboolean
3217 is_callee_gsharedvt_variable (gpointer addr)
3219 MonoJitInfo *ji;
3220 gboolean callee_gsharedvt;
3222 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
3223 g_assert (ji);
3224 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
3225 if (callee_gsharedvt)
3226 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
3227 return callee_gsharedvt;
3230 gpointer
3231 mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
3233 gpointer arg = NULL;
3235 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
3236 arg = mini_method_get_rgctx (method);
3239 * Avoid adding gsharedvt in wrappers since they might not exist if
3240 * this delegate is called through a gsharedvt delegate invoke wrapper.
3241 * Instead, encode that the method is gsharedvt in del->extra_arg,
3242 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
3244 if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
3245 g_assert ((((mgreg_t)arg) & 1) == 0);
3246 arg = (gpointer)(((mgreg_t)arg) | 1);
3248 return arg;
3251 void
3252 mini_init_delegate (MonoDelegate *del)
3254 if (mono_llvm_only)
3255 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
3256 #ifdef ENABLE_INTERPRETER
3257 if (mono_use_interpreter)
3258 mono_interp_init_delegate (del);
3259 #endif
3262 char*
3263 mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
3265 int abs_offset;
3267 abs_offset = offset;
3268 if (abs_offset < 0)
3269 abs_offset = - abs_offset;
3270 return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
3273 gpointer
3274 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
3276 gboolean is_virtual_generic, is_interface, load_imt_reg;
3277 int offset, idx;
3279 static guint8 **cache = NULL;
3280 static int cache_size = 0;
3282 if (!method)
3283 return NULL;
3285 if (MONO_TYPE_ISSTRUCT (sig->ret))
3286 return NULL;
3288 is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
3289 is_interface = mono_class_is_interface (method->klass);
3290 load_imt_reg = is_virtual_generic || is_interface;
3292 if (is_interface)
3293 offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
3294 else
3295 offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
3297 idx = (offset / SIZEOF_VOID_P + MONO_IMT_SIZE) * 2 + (load_imt_reg ? 1 : 0);
3298 g_assert (idx >= 0);
3300 /* Resize the cache to idx + 1 */
3301 if (cache_size < idx + 1) {
3302 mono_jit_lock ();
3303 if (cache_size < idx + 1) {
3304 guint8 **new_cache;
3305 int new_cache_size = idx + 1;
3307 new_cache = g_new0 (guint8*, new_cache_size);
3308 if (cache)
3309 memcpy (new_cache, cache, cache_size * sizeof (guint8*));
3310 g_free (cache);
3312 mono_memory_barrier ();
3313 cache = new_cache;
3314 cache_size = new_cache_size;
3316 mono_jit_unlock ();
3319 if (cache [idx])
3320 return cache [idx];
3322 /* FIXME Support more cases */
3323 if (mono_aot_only) {
3324 cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
3325 g_assert (cache [idx]);
3326 } else {
3327 cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
3329 return cache [idx];
3333 * mini_parse_debug_option:
3334 * @option: The option to parse.
3336 * Parses debug options for the mono runtime. The options are the same as for
3337 * the MONO_DEBUG environment variable.
3340 gboolean
3341 mini_parse_debug_option (const char *option)
3343 if (!strcmp (option, "handle-sigint"))
3344 debug_options.handle_sigint = TRUE;
3345 else if (!strcmp (option, "keep-delegates"))
3346 debug_options.keep_delegates = TRUE;
3347 else if (!strcmp (option, "reverse-pinvoke-exceptions"))
3348 debug_options.reverse_pinvoke_exceptions = TRUE;
3349 else if (!strcmp (option, "collect-pagefault-stats"))
3350 debug_options.collect_pagefault_stats = TRUE;
3351 else if (!strcmp (option, "break-on-unverified"))
3352 debug_options.break_on_unverified = TRUE;
3353 else if (!strcmp (option, "no-gdb-backtrace"))
3354 debug_options.no_gdb_backtrace = TRUE;
3355 else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
3356 debug_options.suspend_on_native_crash = TRUE;
3357 else if (!strcmp (option, "suspend-on-exception"))
3358 debug_options.suspend_on_exception = TRUE;
3359 else if (!strcmp (option, "suspend-on-unhandled"))
3360 debug_options.suspend_on_unhandled = TRUE;
3361 else if (!strcmp (option, "dont-free-domains"))
3362 mono_dont_free_domains = TRUE;
3363 else if (!strcmp (option, "dyn-runtime-invoke"))
3364 debug_options.dyn_runtime_invoke = TRUE;
3365 else if (!strcmp (option, "gdb"))
3366 debug_options.gdb = TRUE;
3367 else if (!strcmp (option, "lldb"))
3368 debug_options.lldb = TRUE;
3369 else if (!strcmp (option, "explicit-null-checks"))
3370 debug_options.explicit_null_checks = TRUE;
3371 else if (!strcmp (option, "gen-seq-points"))
3372 debug_options.gen_sdb_seq_points = TRUE;
3373 else if (!strcmp (option, "gen-compact-seq-points"))
3374 fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
3375 else if (!strcmp (option, "no-compact-seq-points"))
3376 debug_options.no_seq_points_compact_data = TRUE;
3377 else if (!strcmp (option, "single-imm-size"))
3378 debug_options.single_imm_size = TRUE;
3379 else if (!strcmp (option, "init-stacks"))
3380 debug_options.init_stacks = TRUE;
3381 else if (!strcmp (option, "casts"))
3382 debug_options.better_cast_details = TRUE;
3383 else if (!strcmp (option, "soft-breakpoints"))
3384 debug_options.soft_breakpoints = TRUE;
3385 else if (!strcmp (option, "check-pinvoke-callconv"))
3386 debug_options.check_pinvoke_callconv = TRUE;
3387 else if (!strcmp (option, "use-fallback-tls"))
3388 debug_options.use_fallback_tls = TRUE;
3389 else if (!strcmp (option, "debug-domain-unload"))
3390 mono_enable_debug_domain_unload (TRUE);
3391 else if (!strcmp (option, "partial-sharing"))
3392 mono_set_partial_sharing_supported (TRUE);
3393 else if (!strcmp (option, "align-small-structs"))
3394 mono_align_small_structs = TRUE;
3395 else if (!strcmp (option, "native-debugger-break"))
3396 debug_options.native_debugger_break = TRUE;
3397 else if (!strcmp (option, "disable_omit_fp"))
3398 debug_options.disable_omit_fp = TRUE;
3399 else
3400 return FALSE;
3402 return TRUE;
3405 static void
3406 mini_parse_debug_options (void)
3408 char *options = g_getenv ("MONO_DEBUG");
3409 gchar **args, **ptr;
3411 if (!options)
3412 return;
3414 args = g_strsplit (options, ",", -1);
3415 g_free (options);
3417 for (ptr = args; ptr && *ptr; ptr++) {
3418 const char *arg = *ptr;
3420 if (!mini_parse_debug_option (arg)) {
3421 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
3422 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");
3423 exit (1);
3427 g_strfreev (args);
3430 MonoDebugOptions *
3431 mini_get_debug_options (void)
3433 return &debug_options;
3436 static gpointer
3437 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
3439 #if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
3440 return addr;
3441 #else
3442 gpointer* desc = NULL;
3444 if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
3445 return desc;
3446 # ifdef __ia64__
3447 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
3449 desc [0] = addr;
3450 desc [1] = NULL;
3451 # elif defined(__ppc64__) || defined(__powerpc64__)
3453 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
3455 desc [0] = addr;
3456 desc [1] = NULL;
3457 desc [2] = NULL;
3458 # endif
3459 g_hash_table_insert (domain->ftnptrs_hash, addr, desc);
3460 return desc;
3461 #endif
3464 static gpointer
3465 mini_get_addr_from_ftnptr (gpointer descr)
3467 #if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
3468 return *(gpointer*)descr;
3469 #else
3470 return descr;
3471 #endif
3474 static void
3475 register_jit_stats (void)
3477 mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_compiled);
3478 mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
3479 mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
3480 mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
3481 mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
3482 mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
3483 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);
3484 mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
3485 mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
3486 mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
3487 mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
3488 mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
3489 mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
3490 mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
3491 mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
3492 mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
3493 mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
3494 mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
3495 mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
3496 mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
3497 mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
3498 mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
3499 mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
3500 mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
3501 mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
3502 mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
3503 mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
3504 mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
3505 mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
3506 mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
3507 mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
3508 mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
3509 mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
3510 mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
3511 mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
3512 mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
3513 mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
3514 mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
3515 mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
3516 mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
3517 mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
3518 mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
3519 mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
3520 mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
3521 mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
3522 mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
3523 mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
3524 mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
3525 mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
3526 mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
3527 mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
3528 mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
3529 mono_counters_register ("Locals stack size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.locals_stack_size);
3530 mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
3531 mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
3532 mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
3533 mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
3534 mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
3535 mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
3536 mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
3537 mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
3540 static void runtime_invoke_info_free (gpointer value);
3542 static gint
3543 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
3545 const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
3546 const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
3548 return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
3551 static guint
3552 class_method_pair_hash (gconstpointer data)
3554 const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
3556 return (gsize)pair->klass ^ (gsize)pair->method;
3559 static void
3560 mini_create_jit_domain_info (MonoDomain *domain)
3562 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
3564 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3565 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3566 info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
3567 info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
3568 info->runtime_invoke_hash = mono_conc_hashtable_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
3569 info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
3570 info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
3571 info->jump_target_hash = g_hash_table_new (NULL, NULL);
3572 mono_jit_code_hash_init (&info->interp_code_hash);
3574 domain->runtime_info = info;
3577 static void
3578 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
3580 MonoJumpList *jlist = (MonoJumpList *)value;
3581 g_slist_free (jlist->list);
3584 static void
3585 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
3587 GSList *list = (GSList *)value;
3588 g_slist_free (list);
3591 static void
3592 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
3594 MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
3595 mono_code_manager_destroy (di->code_mp);
3596 g_free (di);
3599 static void
3600 runtime_invoke_info_free (gpointer value)
3602 RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
3604 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3605 if (info->dyn_call_info)
3606 mono_arch_dyn_call_free (info->dyn_call_info);
3607 #endif
3608 g_free (info);
3611 static void
3612 free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
3614 g_slist_free (value);
3617 static void
3618 mini_free_jit_domain_info (MonoDomain *domain)
3620 MonoJitDomainInfo *info = domain_jit_info (domain);
3622 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
3623 g_hash_table_destroy (info->jump_target_hash);
3624 if (info->jump_target_got_slot_hash) {
3625 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
3626 g_hash_table_destroy (info->jump_target_got_slot_hash);
3628 if (info->dynamic_code_hash) {
3629 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
3630 g_hash_table_destroy (info->dynamic_code_hash);
3632 if (info->method_code_hash)
3633 g_hash_table_destroy (info->method_code_hash);
3634 g_hash_table_destroy (info->jump_trampoline_hash);
3635 g_hash_table_destroy (info->jit_trampoline_hash);
3636 g_hash_table_destroy (info->delegate_trampoline_hash);
3637 if (info->static_rgctx_trampoline_hash)
3638 g_hash_table_destroy (info->static_rgctx_trampoline_hash);
3639 g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
3640 mono_conc_hashtable_destroy (info->runtime_invoke_hash);
3641 g_hash_table_destroy (info->seq_points);
3642 g_hash_table_destroy (info->arch_seq_points);
3643 if (info->agent_info)
3644 mono_debugger_agent_free_domain_info (domain);
3645 if (info->gsharedvt_arg_tramp_hash)
3646 g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
3647 if (info->llvm_jit_callees) {
3648 g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
3649 g_hash_table_destroy (info->llvm_jit_callees);
3651 #ifdef ENABLE_LLVM
3652 mono_llvm_free_domain_info (domain);
3653 #endif
3655 g_free (domain->runtime_info);
3656 domain->runtime_info = NULL;
3659 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3661 static void
3662 code_manager_chunk_new (void *chunk, int size)
3664 mono_arch_code_chunk_new (chunk, size);
3667 static void
3668 code_manager_chunk_destroy (void *chunk)
3670 mono_arch_code_chunk_destroy (chunk);
3673 #endif
3675 #ifdef ENABLE_LLVM
3676 static gboolean
3677 llvm_init_inner (void)
3679 if (!mono_llvm_load (NULL))
3680 return FALSE;
3682 mono_llvm_init ();
3683 return TRUE;
3685 #endif
3688 * mini_llvm_init:
3690 * Load and initialize LLVM support.
3691 * Return TRUE on success.
3693 gboolean
3694 mini_llvm_init (void)
3696 #ifdef ENABLE_LLVM
3697 static gboolean llvm_inited;
3698 static gboolean init_result;
3700 mono_loader_lock_if_inited ();
3701 if (!llvm_inited) {
3702 init_result = llvm_init_inner ();
3703 llvm_inited = TRUE;
3705 mono_loader_unlock_if_inited ();
3706 return init_result;
3707 #else
3708 return FALSE;
3709 #endif
3712 void
3713 mini_profiler_enable_with_options (const char* profile_options)
3715 mini_enable_profiler = TRUE;
3716 mini_profiler_options = g_strdup (profile_options);
3719 MonoDomain *
3720 mini_init (const char *filename, const char *runtime_version)
3722 MonoError error;
3723 MonoDomain *domain;
3724 MonoRuntimeCallbacks callbacks;
3725 MonoThreadInfoRuntimeCallbacks ticallbacks;
3726 MonoCodeManagerCallbacks code_manager_callbacks;
3728 MONO_VES_INIT_BEGIN ();
3730 CHECKED_MONO_INIT ();
3732 #if defined(__linux__) && !defined(__native_client__)
3733 if (access ("/proc/self/maps", F_OK) != 0) {
3734 g_print ("Mono requires /proc to be mounted.\n");
3735 exit (1);
3737 #endif
3739 mono_os_mutex_init_recursive (&jit_mutex);
3741 mono_cross_helpers_run ();
3743 mono_counters_init ();
3745 mini_jit_init ();
3747 mini_jit_init_job_control ();
3749 /* Happens when using the embedding interface */
3750 if (!default_opt_set)
3751 default_opt = mono_parse_default_optimizations (NULL);
3753 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3754 if (mono_aot_only)
3755 mono_set_generic_sharing_vt_supported (TRUE);
3756 #else
3757 if (mono_llvm_only)
3758 mono_set_generic_sharing_vt_supported (TRUE);
3759 #endif
3761 mono_tls_init_runtime_keys ();
3763 if (!global_codeman)
3764 global_codeman = mono_code_manager_new ();
3766 memset (&callbacks, 0, sizeof (callbacks));
3767 callbacks.create_ftnptr = mini_create_ftnptr;
3768 callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
3769 callbacks.get_runtime_build_info = mono_get_runtime_build_info;
3770 callbacks.set_cast_details = mono_set_cast_details;
3771 callbacks.debug_log = mono_debugger_agent_debug_log;
3772 callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
3773 callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
3774 callbacks.get_imt_trampoline = mini_get_imt_trampoline;
3775 callbacks.imt_entry_inited = mini_imt_entry_inited;
3776 callbacks.init_delegate = mini_init_delegate;
3777 #define JIT_INVOKE_WORKS
3778 #ifdef JIT_INVOKE_WORKS
3779 callbacks.runtime_invoke = mono_jit_runtime_invoke;
3780 #endif
3781 #define JIT_TRAMPOLINES_WORK
3782 #ifdef JIT_TRAMPOLINES_WORK
3783 callbacks.compile_method = mono_jit_compile_method;
3784 callbacks.create_jump_trampoline = mono_create_jump_trampoline;
3785 callbacks.create_jit_trampoline = mono_create_jit_trampoline;
3786 callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
3787 callbacks.free_method = mono_jit_free_method;
3788 #ifndef DISABLE_REMOTING
3789 callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline;
3790 #endif
3791 #endif
3793 mono_install_callbacks (&callbacks);
3795 memset (&ticallbacks, 0, sizeof (ticallbacks));
3796 ticallbacks.setup_async_callback = mono_setup_async_callback;
3797 ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
3798 ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
3799 ticallbacks.thread_state_init = mono_thread_state_init;
3801 #ifndef HOST_WIN32
3802 mono_w32handle_init ();
3803 #endif
3805 mono_threads_runtime_init (&ticallbacks);
3807 if (g_hasenv ("MONO_DEBUG")) {
3808 mini_parse_debug_options ();
3811 mono_code_manager_init ();
3813 memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
3814 #ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
3815 code_manager_callbacks.chunk_new = code_manager_chunk_new;
3816 code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
3817 #endif
3818 mono_code_manager_install_callbacks (&code_manager_callbacks);
3820 mono_hwcap_init ();
3822 mono_arch_cpu_init ();
3824 mono_arch_init ();
3826 mono_unwind_init ();
3828 if (mini_get_debug_options ()->lldb || g_hasenv ("MONO_LLDB")) {
3829 mono_lldb_init ("");
3830 mono_dont_free_domains = TRUE;
3833 #ifdef XDEBUG_ENABLED
3834 char *mono_xdebug = g_getenv ("MONO_XDEBUG");
3835 if (mono_xdebug) {
3836 mono_xdebug_init (mono_xdebug);
3837 g_free (mono_xdebug);
3838 /* So methods for multiple domains don't have the same address */
3839 mono_dont_free_domains = TRUE;
3840 mono_using_xdebug = TRUE;
3841 } else if (mini_get_debug_options ()->gdb) {
3842 mono_xdebug_init ((char*)"gdb");
3843 mono_dont_free_domains = TRUE;
3844 mono_using_xdebug = TRUE;
3846 #endif
3848 #ifdef ENABLE_LLVM
3849 if (mono_use_llvm) {
3850 if (!mono_llvm_load (NULL)) {
3851 mono_use_llvm = FALSE;
3852 fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
3855 if (mono_use_llvm)
3856 mono_llvm_init ();
3857 #endif
3859 mono_trampolines_init ();
3861 if (default_opt & MONO_OPT_AOT)
3862 mono_aot_init ();
3864 mono_debugger_agent_init ();
3866 #ifdef MONO_ARCH_GSHARED_SUPPORTED
3867 mono_set_generic_sharing_supported (TRUE);
3868 #endif
3870 mono_threads_signals_init ();
3872 #ifndef MONO_CROSS_COMPILE
3873 mono_runtime_install_handlers ();
3874 #endif
3875 mono_threads_install_cleanup (mini_thread_cleanup);
3877 #ifdef JIT_TRAMPOLINES_WORK
3878 mono_install_create_domain_hook (mini_create_jit_domain_info);
3879 mono_install_free_domain_hook (mini_free_jit_domain_info);
3880 #endif
3881 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
3882 mono_install_get_class_from_name (mono_aot_get_class_from_name);
3883 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
3885 if (mini_profiler_enabled ()) {
3886 mono_profiler_load (mini_profiler_get_options ());
3887 mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
3890 if (debug_options.collect_pagefault_stats)
3891 mono_aot_set_make_unreadable (TRUE);
3893 if (runtime_version)
3894 domain = mono_init_version (filename, runtime_version);
3895 else
3896 domain = mono_init_from_assembly (filename, filename);
3898 if (mono_aot_only) {
3899 /* This helps catch code allocation requests */
3900 mono_code_manager_set_read_only (domain->code_mp);
3901 mono_marshal_use_aot_wrappers (TRUE);
3904 if (mono_llvm_only) {
3905 mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
3906 mono_set_always_build_imt_trampolines (TRUE);
3907 } else if (mono_aot_only) {
3908 mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
3909 } else {
3910 mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
3913 /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
3914 mono_arch_finish_init ();
3916 mono_icall_init ();
3918 /* This must come after mono_init () in the aot-only case */
3919 mono_exceptions_init ();
3921 /* This should come after mono_init () too */
3922 mini_gc_init ();
3924 #ifndef DISABLE_JIT
3925 mono_create_helper_signatures ();
3926 #endif
3928 register_jit_stats ();
3930 #define JIT_CALLS_WORK
3931 #ifdef JIT_CALLS_WORK
3932 /* Needs to be called here since register_jit_icall depends on it */
3933 mono_marshal_init ();
3935 mono_arch_register_lowlevel_calls ();
3937 register_icalls ();
3939 mono_generic_sharing_init ();
3940 #endif
3942 #ifdef MONO_ARCH_SIMD_INTRINSICS
3943 mono_simd_intrinsics_init ();
3944 #endif
3946 mono_tasklets_init ();
3948 register_trampolines (domain);
3950 if (mono_compile_aot)
3952 * Avoid running managed code when AOT compiling, since the platform
3953 * might only support aot-only execution.
3955 mono_runtime_set_no_exec (TRUE);
3957 mono_mem_account_register_counters ();
3959 #define JIT_RUNTIME_WORKS
3960 #ifdef JIT_RUNTIME_WORKS
3961 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
3962 mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
3963 mono_error_assert_ok (&error);
3964 mono_thread_attach (domain);
3965 #endif
3967 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
3968 mono_runtime_setup_stat_profiler ();
3970 mono_profiler_runtime_initialized ();
3972 MONO_VES_INIT_END ();
3974 return domain;
3977 static void
3978 register_icalls (void)
3980 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
3981 ves_icall_get_frame_info);
3982 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
3983 ves_icall_get_trace);
3984 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
3985 mono_runtime_install_handlers);
3986 mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
3987 mono_runtime_cleanup_handlers);
3989 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
3990 mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
3991 mono_debugger_agent_unhandled_exception);
3992 #endif
3995 * It's important that we pass `TRUE` as the last argument here, as
3996 * it causes the JIT to omit a wrapper for these icalls. If the JIT
3997 * *did* emit a wrapper, we'd be looking at infinite recursion since
3998 * the wrapper would call the icall which would call the wrapper and
3999 * so on.
4001 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
4002 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
4004 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
4005 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
4006 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
4007 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
4008 register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
4009 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
4011 register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
4012 register_icall (mono_llvm_rethrow_exception, "mono_llvm_rethrow_exception", "void object", TRUE);
4013 register_icall (mono_llvm_resume_exception, "mono_llvm_resume_exception", "void", TRUE);
4014 register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
4015 register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
4016 register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
4017 register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
4018 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
4019 register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
4021 // FIXME: This is broken
4022 register_icall (mono_debug_personality, "mono_debug_personality", "int int int ptr ptr ptr", TRUE);
4023 #endif
4025 register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
4026 register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
4027 register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
4028 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
4029 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
4030 register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
4032 #if defined(__native_client__) || defined(__native_client_codegen__)
4033 register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
4034 #endif
4036 if (mono_threads_is_coop_enabled ())
4037 register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
4039 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4040 register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
4041 register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
4042 register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
4043 register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
4044 register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE);
4045 #endif
4046 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
4047 register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE);
4048 register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE);
4049 #endif
4051 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4052 register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE);
4053 register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE);
4054 register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE);
4055 #endif
4057 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4058 register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE);
4059 register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE);
4060 register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE);
4061 register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE);
4062 #endif
4064 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4065 register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE);
4066 #endif
4068 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4069 register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE);
4070 register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
4071 #endif
4073 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
4074 register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
4075 #endif
4077 register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
4078 register_opcode_emulation (OP_RCONV_TO_U8, "__emul_rconv_to_u8", "ulong float", mono_rconv_u8, "mono_rconv_u8", FALSE);
4079 register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
4080 register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
4081 register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
4082 register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
4083 register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
4086 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4087 register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
4088 register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
4089 #endif
4091 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4092 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);
4093 #endif
4094 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4095 register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE);
4096 #endif
4097 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4098 register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE);
4099 #endif
4100 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4101 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);
4102 #endif
4103 #ifdef MONO_ARCH_EMULATE_FREM
4104 #if !defined(__native_client__)
4105 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
4106 register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
4107 #else
4108 register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
4109 #endif
4110 #endif
4112 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4113 if (mono_arch_is_soft_float ()) {
4114 register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
4115 register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
4116 register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
4117 register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
4118 register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
4119 register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
4120 register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
4121 register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
4122 register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
4123 register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4124 register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
4125 register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
4127 #if SIZEOF_VOID_P == 4
4128 register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
4129 #endif
4131 register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
4132 register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
4133 register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
4134 register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
4135 register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
4136 register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
4137 register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
4138 register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
4139 register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
4140 register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
4142 register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
4143 register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
4144 register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
4145 register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
4146 register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
4148 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
4149 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
4150 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
4151 register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
4153 #endif
4154 register_icall (mono_ckfinite, "mono_ckfinite", "double double", FALSE);
4156 #ifdef COMPRESSED_INTERFACE_BITMAP
4157 register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
4158 #endif
4160 #if SIZEOF_REGISTER == 4
4161 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
4162 #else
4163 register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
4164 #endif
4166 /* other jit icalls */
4167 register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
4168 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
4169 "ptr ptr ptr", FALSE);
4170 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
4171 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
4172 "ptr ptr ptr ptr", FALSE);
4173 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
4174 register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
4175 register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
4176 register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
4177 register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
4178 register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
4179 register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
4180 register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
4181 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
4182 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
4183 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
4184 register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
4185 register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
4186 register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
4187 register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
4188 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
4189 register_icall (mono_object_castclass_unbox, "mono_object_castclass_unbox", "object object ptr", FALSE);
4190 register_icall (mono_break, "mono_break", NULL, TRUE);
4191 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
4192 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
4193 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
4194 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
4195 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
4196 register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE);
4197 register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
4198 register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
4199 register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
4200 register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
4201 register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
4203 register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
4205 register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
4206 register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
4207 register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
4208 register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
4209 register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
4211 register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
4213 register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
4214 register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
4215 register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
4216 register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
4218 register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
4219 register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
4220 register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
4221 register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
4222 /* This needs a wrapper so it can have a preserveall cconv */
4223 register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
4224 register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
4225 register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
4226 register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
4227 register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
4228 register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
4229 register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
4231 register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj");
4232 register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr");
4233 register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
4234 register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
4236 #ifdef TARGET_IOS
4237 register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
4238 #endif
4239 /* Register tls icalls */
4240 register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
4241 register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
4242 register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
4243 register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
4244 register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
4245 register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
4246 register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
4247 register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
4248 register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
4249 register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
4252 MonoJitStats mono_jit_stats = {0};
4254 static void
4255 print_jit_stats (void)
4257 if (mono_jit_stats.enabled) {
4258 g_print ("Mono Jit statistics\n");
4259 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4260 mono_jit_stats.max_ratio_method);
4261 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
4262 mono_jit_stats.biggest_method);
4264 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
4265 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4266 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4267 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
4268 g_print ("Methods: %ld\n", mono_stats.method_count);
4269 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4270 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4271 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
4273 g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
4274 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
4275 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
4277 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
4278 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
4279 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
4280 g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
4282 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
4283 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
4284 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
4285 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
4286 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
4287 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
4288 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
4289 g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
4291 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
4292 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
4293 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
4295 g_free (mono_jit_stats.max_ratio_method);
4296 mono_jit_stats.max_ratio_method = NULL;
4297 g_free (mono_jit_stats.biggest_method);
4298 mono_jit_stats.biggest_method = NULL;
4302 void
4303 mini_cleanup (MonoDomain *domain)
4305 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
4306 mono_runtime_shutdown_stat_profiler ();
4308 #ifndef DISABLE_COM
4309 cominterop_release_all_rcws ();
4310 #endif
4312 #ifndef MONO_CROSS_COMPILE
4314 * mono_domain_finalize () needs to be called early since it needs the
4315 * execution engine still fully working (it may invoke managed finalizers).
4317 mono_domain_finalize (domain, 2000);
4318 #endif
4320 /* This accesses metadata so needs to be called before runtime shutdown */
4321 print_jit_stats ();
4323 #ifndef MONO_CROSS_COMPILE
4324 mono_runtime_cleanup (domain);
4325 #endif
4327 mono_threadpool_cleanup ();
4329 mono_profiler_shutdown ();
4331 free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
4333 mono_icall_cleanup ();
4335 mono_runtime_cleanup_handlers ();
4337 #ifndef MONO_CROSS_COMPILE
4338 mono_domain_free (domain, TRUE);
4339 #endif
4341 #ifdef ENABLE_LLVM
4342 if (mono_use_llvm)
4343 mono_llvm_cleanup ();
4344 #endif
4346 mono_aot_cleanup ();
4348 mono_trampolines_cleanup ();
4350 mono_unwind_cleanup ();
4352 mono_code_manager_destroy (global_codeman);
4353 g_free (vtable_trampolines);
4355 mini_jit_cleanup ();
4357 mono_tramp_info_cleanup ();
4359 mono_arch_cleanup ();
4361 mono_generic_sharing_cleanup ();
4363 mono_cleanup ();
4365 mono_trace_cleanup ();
4367 mono_counters_dump (MONO_COUNTER_SECTION_MASK | MONO_COUNTER_MONOTONIC, stdout);
4369 if (mono_inject_async_exc_method)
4370 mono_method_desc_free (mono_inject_async_exc_method);
4372 mono_tls_free_keys ();
4374 mono_os_mutex_destroy (&jit_mutex);
4376 mono_code_manager_cleanup ();
4378 #ifndef HOST_WIN32
4379 mono_w32handle_cleanup ();
4380 #endif
4383 void
4384 mono_set_defaults (int verbose_level, guint32 opts)
4386 mini_verbose = verbose_level;
4387 mono_set_optimizations (opts);
4390 void
4391 mono_disable_optimizations (guint32 opts)
4393 default_opt &= ~opts;
4396 void
4397 mono_set_optimizations (guint32 opts)
4399 default_opt = opts;
4400 default_opt_set = TRUE;
4401 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4402 mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
4403 #else
4404 if (mono_llvm_only)
4405 mono_set_generic_sharing_vt_supported (TRUE);
4406 #endif
4409 void
4410 mono_set_verbose_level (guint32 level)
4412 mini_verbose = level;
4416 * mono_get_runtime_build_info:
4417 * The returned string is owned by the caller. The returned string
4418 * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
4419 * \returns the runtime version + build date in string format.
4421 char*
4422 mono_get_runtime_build_info (void)
4424 if (mono_build_date)
4425 return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
4426 else
4427 return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
4430 static void
4431 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
4433 GHashTable *assemblies = (GHashTable*)user_data;
4434 MonoImage *image = mono_assembly_get_image (ass);
4435 MonoMethod *method, *invoke;
4436 int i, count = 0;
4438 if (g_hash_table_lookup (assemblies, ass))
4439 return;
4441 g_hash_table_insert (assemblies, ass, ass);
4443 if (mini_verbose > 0)
4444 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
4446 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4447 MonoError error;
4449 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4450 if (!method) {
4451 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4452 continue;
4454 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
4455 continue;
4456 if (method->is_generic || mono_class_is_gtd (method->klass))
4457 continue;
4459 count++;
4460 if (mini_verbose > 1) {
4461 char * desc = mono_method_full_name (method, TRUE);
4462 g_print ("Compiling %d %s\n", count, desc);
4463 g_free (desc);
4465 mono_compile_method_checked (method, &error);
4466 if (!is_ok (&error)) {
4467 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4468 continue;
4470 if (strcmp (method->name, "Finalize") == 0) {
4471 invoke = mono_marshal_get_runtime_invoke (method, FALSE);
4472 mono_compile_method_checked (invoke, &error);
4473 mono_error_assert_ok (&error);
4475 #ifndef DISABLE_REMOTING
4476 if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
4477 invoke = mono_marshal_get_remoting_invoke_with_check (method);
4478 mono_compile_method_checked (invoke, &error);
4479 mono_error_assert_ok (&error);
4481 #endif
4484 /* Load and precompile referenced assemblies as well */
4485 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
4486 mono_assembly_load_reference (image, i);
4487 if (image->references [i])
4488 mono_precompile_assembly (image->references [i], assemblies);
4492 void mono_precompile_assemblies ()
4494 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
4496 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
4498 g_hash_table_destroy (assemblies);
4502 * Used by LLVM.
4503 * Have to export this for AOT.
4505 void
4506 mono_personality (void)
4508 /* Not used */
4509 g_assert_not_reached ();
4512 // Custom handlers currently only implemented by Windows.
4513 #ifndef HOST_WIN32
4514 gboolean
4515 mono_runtime_install_custom_handlers (const char *handlers)
4517 return FALSE;
4520 void
4521 mono_runtime_install_custom_handlers_usage (void)
4523 fprintf (stdout,
4524 "Custom Handlers:\n"
4525 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
4526 " separated list of available handlers to install.\n"
4527 "\n"
4528 "No handlers supported on current platform.\n");
4530 #endif /* HOST_WIN32 */