#include "debug-mini.h"
#include "mini-gc.h"
-static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
-static gpointer mono_jit_compile_method (MonoMethod *method);
+static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
/* helper methods signature */
/* FIXME: Make these static again */
void
mono_jit_thread_attach (MonoDomain *domain)
{
+ if (!domain)
+ /*
+ * Happens when called from AOTed code which is only used in the root
+ * domain.
+ */
+ domain = mono_get_root_domain ();
+
#ifdef HAVE_KW_THREAD
if (!mono_lmf_addr) {
mono_thread_attach (domain);
MonoThread *thread;
void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
thread = mono_thread_current ();
- mono_debugger_thread_created (tid, thread, jit_tls);
+ mono_debugger_thread_created (tid, thread, jit_tls, func);
if (thread)
thread->jit_data = jit_tls;
}
MonoThread *thread;
void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
thread = mono_thread_current ();
- mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
+ mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls, NULL);
if (thread)
thread->jit_data = jit_tls;
if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_DECLSEC:
return (ji->type << 8) | ji->data.token->token;
+ case MONO_PATCH_INFO_INTERNAL_METHOD:
+ return (ji->type << 8) | g_str_hash (ji->data.name);
case MONO_PATCH_INFO_VTABLE:
case MONO_PATCH_INFO_CLASS:
case MONO_PATCH_INFO_IID:
case MONO_PATCH_INFO_METHOD:
case MONO_PATCH_INFO_METHOD_JUMP:
case MONO_PATCH_INFO_IMAGE:
- case MONO_PATCH_INFO_INTERNAL_METHOD:
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_SFLDA:
(ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
return 0;
break;
+ case MONO_PATCH_INFO_INTERNAL_METHOD:
+ return g_str_equal (ji1->data.name, ji2->data.name);
+
+ case MONO_PATCH_INFO_RGCTX_FETCH: {
+ MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
+ MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
+
+ 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);
+ }
+
default:
if (ji1->data.target != ji2->data.target)
return 0;
target = code;
} else {
/* get the trampoline to the method from the domain */
- if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
- target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
- patch_info->data.method);
- } else {
- target = mono_create_jit_trampoline (patch_info->data.method);
- }
+ target = mono_create_jit_trampoline (patch_info->data.method);
}
break;
case MONO_PATCH_INFO_SWITCH: {
} else {
mono_domain_code_commit (cfg->domain, cfg->native_code, cfg->code_size, cfg->code_len);
}
+ mono_profiler_code_buffer_new (code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method);
mono_arch_flush_icache (cfg->native_code, cfg->code_len);
}
static gpointer
-mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
+mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoException **jit_ex)
{
MonoCompile *cfg;
gpointer code = NULL;
MonoJitInfo *info;
MonoVTable *vtable;
+ MonoException *ex = NULL;
#ifdef MONO_USE_AOT_COMPILER
if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
case MONO_EXCEPTION_BAD_IMAGE: {
/* Throw a type load exception if needed */
MonoLoaderError *error = mono_loader_get_last_error ();
- MonoException *ex;
if (error) {
ex = mono_loader_error_prepare_exception (error);
g_assert_not_reached ();
}
}
- mono_destroy_compile (cfg);
- mono_raise_exception (ex);
break;
}
- case MONO_EXCEPTION_INVALID_PROGRAM: {
- MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
- mono_destroy_compile (cfg);
- mono_raise_exception (ex);
+ case MONO_EXCEPTION_INVALID_PROGRAM:
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
break;
- }
- case MONO_EXCEPTION_UNVERIFIABLE_IL: {
- MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
- mono_destroy_compile (cfg);
- mono_raise_exception (ex);
+ case MONO_EXCEPTION_UNVERIFIABLE_IL:
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
break;
- }
- case MONO_EXCEPTION_METHOD_ACCESS: {
- MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
- mono_destroy_compile (cfg);
- mono_raise_exception (ex);
+ case MONO_EXCEPTION_METHOD_ACCESS:
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
break;
- }
- case MONO_EXCEPTION_FIELD_ACCESS: {
- MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
- mono_destroy_compile (cfg);
- mono_raise_exception (ex);
+ case MONO_EXCEPTION_FIELD_ACCESS:
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
break;
- }
/* this can only be set if the security manager is active */
case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
MonoSecurityManager* secman = mono_security_manager_get_methods ();
args [1] = &method;
mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
- mono_destroy_compile (cfg);
- cfg = NULL;
-
- mono_raise_exception ((MonoException*)exc);
+ ex = (MonoException*)exc;
+ break;
}
case MONO_EXCEPTION_OBJECT_SUPPLIED: {
MonoException *exp = cfg->exception_ptr;
MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
- mono_destroy_compile (cfg);
- mono_raise_exception (exp);
+
+ ex = exp;
break;
}
default:
g_assert_not_reached ();
}
+ if (ex) {
+ mono_destroy_compile (cfg);
+ *jit_ex = ex;
+ return NULL;
+ }
+
mono_loader_lock (); /*FIXME lookup_method_inner requires the loader lock*/
mono_domain_lock (target_domain);
}
static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
{
MonoDomain *target_domain, *domain = mono_domain_get ();
MonoJitInfo *info;
- gpointer p;
+ gpointer code, p;
MonoJitICallInfo *callinfo = NULL;
/*
}
}
- p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
+ code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
+ if (!code)
+ return NULL;
+
+ p = mono_create_ftnptr (target_domain, code);
if (callinfo) {
mono_jit_lock ();
return p;
}
-static gpointer
+gpointer
mono_jit_compile_method (MonoMethod *method)
{
- return mono_jit_compile_method_with_opt (method, default_opt);
+ MonoException *ex = NULL;
+ gpointer code;
+
+ code = mono_jit_compile_method_with_opt (method, default_opt, &ex);
+ if (!code) {
+ g_assert (ex);
+ mono_raise_exception (ex);
+ }
+
+ return code;
}
#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
mono_internal_hash_table_remove (&domain->jit_code_hash, method);
g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
+ g_hash_table_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
mono_domain_unlock (domain);
#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
}
+typedef struct {
+ MonoMethod *method;
+ gpointer compiled_method;
+ gpointer runtime_invoke;
+ MonoVTable *vtable;
+} RuntimeInvokeInfo;
+
/**
* mono_jit_runtime_invoke:
* @method: the method to invoke
static MonoObject*
mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
{
- MonoMethod *to_compile;
MonoMethod *invoke;
MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
- void* compiled_method;
- MonoVTable *vtable;
- gboolean need_rgctx_tramp = FALSE;
-
+ MonoDomain *domain = mono_domain_get ();
+ MonoJitDomainInfo *domain_info;
+ RuntimeInvokeInfo *info, *info2;
+
if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
return NULL;
}
- to_compile = method;
+ domain_info = domain_jit_info (domain);
- if (mono_method_needs_static_rgctx_invoke (method, FALSE))
- need_rgctx_tramp = TRUE;
+ mono_domain_lock (domain);
+ info = g_hash_table_lookup (domain_info->runtime_invoke_hash, method);
+ mono_domain_unlock (domain);
- /* Special case parameterless ctors to speed up Activator.CreateInstance () */
- if (method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !strcmp (method->name, ".ctor") && mono_method_signature (method)->param_count == 0 && !method->klass->valuetype) {
- MonoJitDomainInfo *domain_info = domain_jit_info (mono_domain_get ());
+ if (!info) {
+ info = g_new0 (RuntimeInvokeInfo, 1);
- if (!domain_info->ctor_runtime_invoke) {
- invoke = mono_marshal_get_runtime_invoke (method, FALSE);
- domain_info->ctor_runtime_invoke = mono_jit_compile_method (invoke);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ info->runtime_invoke = mono_jit_compile_method (invoke);
+ info->vtable = mono_class_vtable (domain, method->klass);
+ g_assert (info->vtable);
+
+ if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
+ /*
+ * Array Get/Set/Address methods. The JIT implements them using inline code
+ * inside the runtime invoke wrappers, so no need to compile them.
+ */
+ info->compiled_method = NULL;
+ } else {
+ MonoException *jit_ex = NULL;
+
+ info->compiled_method = mono_jit_compile_method_with_opt (method, default_opt, &jit_ex);
+ if (!info->compiled_method) {
+ g_free (info);
+ g_assert (jit_ex);
+ if (exc) {
+ *exc = (MonoObject*)jit_ex;
+ return NULL;
+ } else {
+ mono_raise_exception (jit_ex);
+ }
+ }
+
+ if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+ info->compiled_method = mono_create_static_rgctx_trampoline (method, info->compiled_method);
}
- runtime_invoke = domain_info->ctor_runtime_invoke;
- } else {
- invoke = mono_marshal_get_runtime_invoke (method, FALSE);
- runtime_invoke = mono_jit_compile_method (invoke);
+ mono_domain_lock (domain);
+ info2 = g_hash_table_lookup (domain_info->runtime_invoke_hash, method);
+ if (info2) {
+ g_free (info);
+ info = info2;
+ } else {
+ g_hash_table_insert (domain_info->runtime_invoke_hash, method, info);
+ }
+ mono_domain_unlock (domain);
}
+ runtime_invoke = info->runtime_invoke;
+
/*
* We need this here because mono_marshal_get_runtime_invoke can place
* the helper method in System.Object and not the target class.
*/
- vtable = mono_class_vtable (mono_domain_get (), method->klass);
- g_assert (vtable);
- mono_runtime_class_init (vtable);
+ mono_runtime_class_init (info->vtable);
- if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
- (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
- /*
- * Array Get/Set/Address methods. The JIT implements them using inline code
- * inside the runtime invoke wrappers, so no need to compile them.
- */
- compiled_method = NULL;
- } else {
- compiled_method = mono_jit_compile_method (to_compile);
- }
- if (need_rgctx_tramp)
- compiled_method = mono_create_static_rgctx_trampoline (to_compile, compiled_method);
-
- return runtime_invoke (obj, params, exc, compiled_method);
+ return runtime_invoke (obj, params, exc, info->compiled_method);
}
void
{
return &debug_options;
}
+
+static gpointer
+mini_create_ftnptr (MonoDomain *domain, gpointer addr)
+{
+#ifdef __ia64__
+ gpointer *desc;
+
+ desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
+
+ desc [0] = addr;
+ desc [1] = NULL;
+
+ return desc;
+#elif defined(__ppc64__) || defined(__powerpc64__)
+ gpointer *desc;
+
+ desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
+
+ desc [0] = addr;
+ desc [1] = NULL;
+ desc [2] = NULL;
+
+ return desc;
+#else
+ return addr;
+#endif
+}
+
+static gpointer
+mini_get_addr_from_ftnptr (gpointer descr)
+{
+#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
+ return *(gpointer*)descr;
+#else
+ return descr;
+#endif
+}
static void
mini_create_jit_domain_info (MonoDomain *domain)
info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
info->static_rgctx_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ info->runtime_invoke_hash = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free);
domain->runtime_info = info;
}
g_hash_table_destroy (info->delegate_trampoline_hash);
g_hash_table_destroy (info->static_rgctx_trampoline_hash);
g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
+ g_hash_table_destroy (info->runtime_invoke_hash);
g_free (domain->runtime_info);
domain->runtime_info = NULL;
mini_init (const char *filename, const char *runtime_version)
{
MonoDomain *domain;
+ MonoRuntimeCallbacks callbacks;
MONO_PROBE_VES_INIT_BEGIN ();
InitializeCriticalSection (&jit_mutex);
+#ifdef MONO_DEBUGGER_SUPPORTED
+ if (mini_debug_running_inside_mdb ())
+ mini_debugger_init ();
+#endif
+
+#ifdef MONO_ARCH_HAVE_TLS_GET
+ mono_runtime_set_has_tls_get (TRUE);
+#else
+ mono_runtime_set_has_tls_get (FALSE);
+#endif
+
if (!global_codeman)
global_codeman = mono_code_manager_new ();
jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ memset (&callbacks, 0, sizeof (callbacks));
+ callbacks.create_ftnptr = mini_create_ftnptr;
+ callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
+
+ mono_install_callbacks (&callbacks);
+
mono_arch_cpu_init ();
mono_arch_init ();
mono_set_generic_sharing_supported (TRUE);
#endif
+#ifndef MONO_CROSS_COMPILE
mono_runtime_install_handlers ();
+#endif
mono_threads_install_cleanup (mini_thread_cleanup);
#ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
#ifndef DISABLE_COM
cominterop_release_all_rcws ();
#endif
-
+
+#ifndef MONO_CROSS_COMPILE
/*
* mono_runtime_cleanup() and mono_domain_finalize () need to
* be called early since they need the execution engine still
* and mono_runtime_cleanup will wait for other threads to finish).
*/
mono_domain_finalize (domain, 2000);
+#endif
/* This accesses metadata so needs to be called before runtime shutdown */
print_jit_stats ();
+#ifndef MONO_CROSS_COMPILE
mono_runtime_cleanup (domain);
+#endif
mono_profiler_shutdown ();