X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-runtime.c;h=136239a1211c7c217c32221e20bcd5faccc72aa4;hb=a341404ecdd3b5ca2ed0ab1e9a5bcb9b5ccd2566;hp=bb4181859b6caacbb062a1a9ba4a171d40df0d04;hpb=9ca4e0ee281f868170cd032ba508fa38a27d69a4;p=mono.git diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index bb4181859b6..136239a1211 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -79,6 +81,7 @@ #ifdef MONO_ARCH_LLVM_SUPPORTED #ifdef ENABLE_LLVM #include "mini-llvm-cpp.h" +#include "llvm-jit.h" #endif #endif @@ -629,10 +632,15 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile) wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc); g_free (name); - if (do_compile) + if (do_compile) { trampoline = mono_compile_method (wrapper); - else - trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper)); + } else { + MonoError error; + + trampoline = mono_create_jit_trampoline (domain, wrapper, &error); + mono_error_assert_ok (&error); + trampoline = mono_create_ftnptr (domain, (gpointer)trampoline); + } mono_loader_lock (); if (!callinfo->trampoline) { @@ -710,6 +718,19 @@ register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr) mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name); } +static void +register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr) +{ + MonoMethodSignature *sig; + + if (sigstr) + sig = mono_create_icall_signature (sigstr); + else + sig = NULL; + + mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL); +} + static void register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save) { @@ -810,7 +831,8 @@ mono_get_lmf_addr (void) * mono_get_lmf_addr, and mono_get_lmf_addr requires the thread to be attached. */ - mono_jit_thread_attach (NULL); + mono_thread_attach (mono_get_root_domain ()); + mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background); if ((jit_tls = mono_native_tls_get_value (mono_jit_tls_id))) return &jit_tls->lmf; @@ -869,48 +891,119 @@ mono_set_lmf_addr (gpointer lmf_addr) } /* - * mono_jit_thread_attach: + * mono_jit_thread_attach: called by native->managed wrappers * - * Called by native->managed wrappers. Returns the original domain which needs to be - * restored, or NULL. + * In non-coop mode: + * - @dummy: is NULL + * - @return: the original domain which needs to be restored, or NULL. + * + * In coop mode: + * - @dummy: contains the original domain + * - @return: a cookie containing current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise */ -MonoDomain* -mono_jit_thread_attach (MonoDomain *domain) +gpointer +mono_jit_thread_attach (MonoDomain *domain, gpointer *dummy) { MonoDomain *orig; - if (!domain) - /* - * Happens when called from AOTed code which is only used in the root - * domain. - */ + if (!domain) { + /* Happens when called from AOTed code which is only used in the root domain. */ domain = mono_get_root_domain (); + } + + g_assert (domain); + + if (!mono_threads_is_coop_enabled ()) { + gboolean attached; #ifdef MONO_HAVE_FAST_TLS - if (!MONO_FAST_TLS_GET (mono_lmf_addr)) { - mono_thread_attach (domain); - // #678164 - mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background); - } + attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL; #else - if (!mono_native_tls_get_value (mono_jit_tls_id)) { - mono_thread_attach (domain); - mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background); - } + attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL; #endif - orig = mono_domain_get (); - if (orig != domain) - mono_domain_set (domain, TRUE); - return orig != domain ? orig : NULL; + if (!attached) { + mono_thread_attach (domain); + + // #678164 + mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background); + } + + orig = mono_domain_get (); + if (orig != domain) + mono_domain_set (domain, TRUE); + + return orig != domain ? orig : NULL; + } else { + MonoThreadInfo *info; + + info = mono_thread_info_current_unchecked (); + if (!info || !mono_thread_info_is_live (info)) { + /* thread state STARTING -> RUNNING */ + mono_thread_attach (domain); + + // #678164 + mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background); + + *dummy = NULL; + + /* mono_threads_reset_blocking_start returns the current MonoThreadInfo + * if we were in BLOCKING mode */ + return mono_thread_info_current (); + } else { + orig = mono_domain_get (); + + /* orig might be null if we did an attach -> detach -> attach sequence */ + + if (orig != domain) + mono_domain_set (domain, TRUE); + + *dummy = orig; + + /* thread state (BLOCKING|RUNNING) -> RUNNING */ + return mono_threads_reset_blocking_start (dummy); + } + } } -/* Called by native->managed wrappers */ +/* + * mono_jit_thread_detach: called by native->managed wrappers + * + * In non-coop mode: + * - @cookie: the original domain which needs to be restored, or NULL. + * - @dummy: is NULL + * + * In coop mode: + * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise + * - @dummy: contains the original domain + */ void -mono_jit_set_domain (MonoDomain *domain) +mono_jit_thread_detach (gpointer cookie, gpointer *dummy) { - if (domain) - mono_domain_set (domain, TRUE); + MonoDomain *domain, *orig; + + if (!mono_threads_is_coop_enabled ()) { + orig = (MonoDomain*) cookie; + + if (orig) + mono_domain_set (orig, TRUE); + } else { + orig = (MonoDomain*) *dummy; + + domain = mono_domain_get (); + g_assert (domain); + + /* it won't do anything if cookie is NULL + * thread state RUNNING -> (RUNNING|BLOCKING) */ + mono_threads_reset_blocking_end (cookie, dummy); + + if (orig != domain) { + if (!orig) + mono_domain_unset (); + else + mono_domain_set (orig, TRUE); + } + } } /** @@ -1215,6 +1308,7 @@ mono_patch_info_hash (gconstpointer data) case MONO_PATCH_INFO_METHOD_JUMP: case MONO_PATCH_INFO_IMAGE: case MONO_PATCH_INFO_ICALL_ADDR: + case MONO_PATCH_INFO_ICALL_ADDR_CALL: case MONO_PATCH_INFO_FIELD: case MONO_PATCH_INFO_SFLDA: case MONO_PATCH_INFO_SEQ_POINT_INFO: @@ -1262,6 +1356,8 @@ mono_patch_info_hash (gconstpointer data) } case MONO_PATCH_INFO_JIT_ICALL_ADDR: return (ji->type << 8) | g_str_hash (ji->data.target); + case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER: + return (ji->type << 8) | mono_signature_hash (ji->data.sig); default: printf ("info type: %d\n", ji->type); mono_print_ji (ji); printf ("\n"); @@ -1326,6 +1422,8 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) if (ji1->data.target == ji2->data.target) return 1; return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0; + case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER: + return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0; default: if (ji1->data.target != ji2->data.target) return 0; @@ -1336,11 +1434,13 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) } gpointer -mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors) +mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error) { unsigned char *ip = patch_info->ip.i + code; gconstpointer target = NULL; + mono_error_init (error); + switch (patch_info->type) { case MONO_PATCH_INFO_BB: /* @@ -1387,7 +1487,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, break; } case MONO_PATCH_INFO_METHOD_JUMP: - target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE); + target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error); + if (!mono_error_ok (error)) + return NULL; #if defined(__native_client__) && defined(__native_client_codegen__) # if defined(TARGET_AMD64) /* This target is an absolute address, not relative to the */ @@ -1403,13 +1505,17 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, * avoid trampoline, as we not yet know where we will * be installed. */ - target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method); + target = mono_create_jit_trampoline (domain, patch_info->data.method, error); + if (!mono_error_ok (error)) + return NULL; #else if (patch_info->data.method == method) { target = code; } else { /* get the trampoline to the method from the domain */ - target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method); + target = mono_create_jit_trampoline (domain, patch_info->data.method, error); + if (!mono_error_ok (error)) + return NULL; } #endif break; @@ -1524,8 +1630,11 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, /* Done by the generated code */ ; else { - if (run_cctors) - mono_runtime_class_init (vtable); + if (run_cctors) { + if (!mono_runtime_class_init_full (vtable, error)) { + return NULL; + } + } } target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset; break; @@ -1553,28 +1662,27 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, case MONO_PATCH_INFO_TYPE_FROM_HANDLE: { gpointer handle; MonoClass *handle_class; - MonoError error; handle = mono_ldtoken_checked (patch_info->data.token->image, - patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error); - if (!mono_error_ok (&error)) - g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error)); + patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error); + if (!mono_error_ok (error)) + g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error)); mono_class_init (handle_class); mono_class_init (mono_class_from_mono_type ((MonoType *)handle)); - target = - mono_type_get_object (domain, (MonoType *)handle); + target = mono_type_get_object_checked (domain, (MonoType *)handle, error); + if (!mono_error_ok (error)) + return NULL; break; } case MONO_PATCH_INFO_LDTOKEN: { gpointer handle; MonoClass *handle_class; - MonoError error; handle = mono_ldtoken_checked (patch_info->data.token->image, - patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error); - if (!mono_error_ok (&error)) - g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error)); + patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error); + if (!mono_error_ok (error)) + g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error)); mono_class_init (handle_class); target = handle; @@ -1584,6 +1692,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2); break; case MONO_PATCH_INFO_ICALL_ADDR: + case MONO_PATCH_INFO_ICALL_ADDR_CALL: /* run_cctors == 0 -> AOT */ if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { const char *exc_class; @@ -1592,8 +1701,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, if (run_cctors) { target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg); if (!target) { - if (mono_aot_only) - mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg)); + if (mono_aot_only) { + mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg)); + return NULL; + } 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)); } } else { @@ -1698,6 +1809,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, break; } + case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER: + target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE); + break; default: g_assert_not_reached (); } @@ -1837,7 +1951,7 @@ no_gsharedvt_in_wrapper (void) } static gpointer -mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex) +mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *error) { MonoDomain *target_domain, *domain = mono_domain_get (); MonoJitInfo *info; @@ -1846,6 +1960,8 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException MonoJitICallInfo *callinfo = NULL; WrapperInfo *winfo = NULL; + mono_error_init (error); + /* * ICALL wrappers are handled specially, since there is only one copy of them * shared by all appdomains. @@ -1878,9 +1994,8 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException ctx = mono_method_get_context (method); method = info->d.synchronized_inner.method; if (ctx) { - MonoError error; - method = mono_class_inflate_generic_method_checked (method, ctx, &error); - g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ + method = mono_class_inflate_generic_method_checked (method, ctx, error); + g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */ } } } @@ -1890,7 +2005,6 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException /* We can't use a domain specific method in another domain */ if (! ((domain != target_domain) && !info->domain_neutral)) { MonoVTable *vtable; - MonoException *tmpEx; mono_jit_stats.methods_lookups++; @@ -1901,11 +2015,8 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException } g_assert (vtable); - tmpEx = mono_runtime_class_init_full (vtable, ex == NULL); - if (tmpEx) { - *ex = tmpEx; + if (!mono_runtime_class_init_full (vtable, error)) return NULL; - } return mono_create_ftnptr (target_domain, info->code_start); } } @@ -1927,15 +2038,13 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException if (!mono_llvm_only) { vtable = mono_class_vtable (domain, method->klass); g_assert (vtable); - mono_runtime_class_init (vtable); + if (!mono_runtime_class_init_full (vtable, error)) + return NULL; } } } #endif - if (!code) - code = mono_jit_compile_method_inner (method, target_domain, opt, ex); - if (!code && mono_llvm_only) { if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) { WrapperInfo *info = mono_marshal_get_wrapper_info (method); @@ -1949,7 +2058,14 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException return no_gsharedvt_in_wrapper; } } + } + + if (!code) + code = mono_jit_compile_method_inner (method, target_domain, opt, error); + if (!mono_error_ok (error)) + return NULL; + if (!code && mono_llvm_only) { printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1)); g_assert_not_reached (); } @@ -1985,17 +2101,11 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException } gpointer -mono_jit_compile_method (MonoMethod *method) +mono_jit_compile_method (MonoMethod *method, MonoError *error) { - MonoException *ex = NULL; gpointer code; - code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), &ex); - if (!code) { - g_assert (ex); - mono_raise_exception (ex); - } - + code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), error); return code; } @@ -2060,7 +2170,6 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method) } g_slist_free (remove); } - mono_domain_unlock (domain); #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD @@ -2117,6 +2226,32 @@ mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *met return NULL; } +static guint32 bisect_opt = 0; +static GHashTable *bisect_methods_hash = NULL; + +void +mono_set_bisect_methods (guint32 opt, const char *method_list_filename) +{ + FILE *file; + char method_name [2048]; + + bisect_opt = opt; + bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal); + g_assert (bisect_methods_hash); + + file = fopen (method_list_filename, "r"); + g_assert (file); + + while (fgets (method_name, sizeof (method_name), file)) { + size_t len = strlen (method_name); + g_assert (len > 0); + g_assert (method_name [len - 1] == '\n'); + method_name [len - 1] = 0; + g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1)); + } + g_assert (feof (file)); +} + gboolean mono_do_single_method_regression = FALSE; guint32 mono_single_method_regression_opt = 0; MonoMethod *mono_current_single_method; @@ -2128,6 +2263,13 @@ mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt) { g_assert (method); + if (bisect_methods_hash) { + char *name = mono_method_full_name (method, TRUE); + void *res = g_hash_table_lookup (bisect_methods_hash, name); + g_free (name); + if (res) + return default_opt | bisect_opt; + } if (!mono_do_single_method_regression) return default_opt; if (!mono_current_single_method) { @@ -2157,39 +2299,25 @@ typedef struct { MonoVTable *vtable; MonoDynCallInfo *dyn_call_info; MonoClass *ret_box_class; - gboolean needs_rgctx; MonoMethodSignature *sig; + gboolean gsharedvt_invoke; gpointer *wrapper_arg; } RuntimeInvokeInfo; -gboolean -mini_gsharedvt_runtime_invoke_supported (MonoMethodSignature *sig) -{ - gboolean supported = TRUE; - int i; - - for (i = 0; i < sig->param_count; ++i) { - MonoType *t = sig->params [i]; - - if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) - supported = FALSE; - } - - return supported; -} - static RuntimeInvokeInfo* -create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method) +create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error) { MonoMethod *invoke; RuntimeInvokeInfo *info; info = g_new0 (RuntimeInvokeInfo, 1); - info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE); info->compiled_method = compiled_method; + info->sig = mono_method_signature (method); - invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx); - info->vtable = mono_class_vtable_full (domain, method->klass, TRUE); + invoke = mono_marshal_get_runtime_invoke (method, FALSE); + info->vtable = mono_class_vtable_full (domain, method->klass, error); + if (!mono_error_ok (error)) + return NULL; g_assert (info->vtable); MonoMethodSignature *sig = mono_method_signature (method); @@ -2207,7 +2335,6 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com if (method->string_ctor) sig = mono_marshal_get_string_ctor_signature (method); - g_assert (!info->needs_rgctx); for (i = 0; i < sig->param_count; ++i) { MonoType *t = sig->params [i]; @@ -2267,54 +2394,145 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com if (!info->dyn_call_info) { if (mono_llvm_only) { - gboolean supported; - - supported = mini_gsharedvt_runtime_invoke_supported (sig); - - if (mono_class_is_contextbound (method->klass) || !info->compiled_method) - supported = FALSE; - #ifndef ENABLE_GSHAREDVT - supported = FALSE; + g_assert_not_reached (); #endif - - if (supported) { + info->gsharedvt_invoke = TRUE; + if (!callee_gsharedvt) { /* Invoke a gsharedvt out wrapper instead */ MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig); MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count); info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer)); - info->wrapper_arg [0] = info->compiled_method; - info->wrapper_arg [1] = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL; + info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1])); /* Pass has_rgctx == TRUE since the wrapper has an extra arg */ invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig); g_free (wrapper_sig); - info->compiled_method = mono_jit_compile_method (wrapper); + info->compiled_method = mono_jit_compile_method (wrapper, error); + if (!mono_error_ok (error)) { + g_free (info); + return NULL; + } + } else { + /* Gsharedvt methods can be invoked the same way */ + /* The out wrapper has the same signature as the compiled gsharedvt method */ + MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count); + + info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL; + + invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig); + g_free (wrapper_sig); } } - info->runtime_invoke = mono_jit_compile_method (invoke); + info->runtime_invoke = mono_jit_compile_method (invoke, error); + if (!mono_error_ok (error)) { + g_free (info); + return NULL; + } } return info; } +static MonoObject* +mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error) +{ + MonoMethodSignature *sig = info->sig; + MonoDomain *domain = mono_domain_get (); + MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method); + gpointer *args; + gpointer retval_ptr; + guint8 retval [256]; + gpointer *param_refs; + int i, pindex; + + mono_error_init (error); + + g_assert (info->gsharedvt_invoke); + + /* + * Instead of invoking the method directly, we invoke a gsharedvt out wrapper. + * The advantage of this is the gsharedvt out wrappers have a reduced set of + * signatures, so we only have to generate runtime invoke wrappers for these + * signatures. + * This code also handles invocation of gsharedvt methods directly, no + * out wrappers are used in that case. + */ + args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer)); + param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer)); + pindex = 0; + /* + * The runtime invoke wrappers expects pointers to primitive types, so have to + * use indirections. + */ + if (sig->hasthis) + args [pindex ++] = &obj; + if (sig->ret->type != MONO_TYPE_VOID) { + retval_ptr = (gpointer)&retval; + args [pindex ++] = &retval_ptr; + } + for (i = 0; i < sig->param_count; ++i) { + MonoType *t = sig->params [i]; + + if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) { + MonoClass *klass = mono_class_from_mono_type (t); + guint8 *nullable_buf; + int size; + + size = mono_class_value_size (klass, NULL); + nullable_buf = g_alloca (size); + g_assert (nullable_buf); + + /* The argument pointed to by params [i] is either a boxed vtype or null */ + mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass); + params [i] = nullable_buf; + } + + if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) { + param_refs [i] = params [i]; + params [i] = &(param_refs [i]); + } + args [pindex ++] = ¶ms [i]; + } + /* The gsharedvt out wrapper has an extra argument which contains the method to call */ + args [pindex ++] = &info->wrapper_arg; + + runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke; + + runtime_invoke (NULL, args, exc, info->compiled_method); + if (exc && *exc) + mono_error_set_exception_instance (error, (MonoException*) *exc); + + if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class) + return mono_value_box (domain, info->ret_box_class, retval); + else + return *(MonoObject**)retval; +} + /** * mono_jit_runtime_invoke: * @method: the method to invoke * @obj: this pointer * @params: array of parameter values. - * @exc: used to catch exceptions objects + * @exc: Set to the exception raised in the managed method. If NULL, error is thrown instead. + * If coop is enabled, this argument is ignored - all exceptoins are caught and propagated + * through @error + * @error: error or caught exception object */ static MonoObject* -mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc) +mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error) { MonoMethod *invoke, *callee; MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method); MonoDomain *domain = mono_domain_get (); MonoJitDomainInfo *domain_info; RuntimeInvokeInfo *info, *info2; + MonoJitInfo *ji = NULL; + gboolean callee_gsharedvt = FALSE; + + mono_error_init (error); 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"); @@ -2332,11 +2550,11 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec * but keep it just in case for moonlight. */ mono_class_setup_vtable (method->klass); - if (method->klass->exception_type != MONO_EXCEPTION_NONE) { + if (mono_class_has_failure (method->klass)) { + MonoException *fail_exc = mono_class_get_exception_for_failure (method->klass); if (exc) - *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass); - else - mono_raise_exception (mono_class_get_exception_for_failure (method->klass)); + *exc = (MonoObject*)fail_exc; + mono_error_set_exception_instance (error, fail_exc); return NULL; } } @@ -2357,7 +2575,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec MonoMethod *wrapper; wrapper = mono_marshal_get_array_accessor_wrapper (method); - invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE, FALSE); + invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE); callee = wrapper; } else { callee = NULL; @@ -2365,26 +2583,28 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec } if (callee) { - MonoException *jit_ex = NULL; - - compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex); + compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), error); if (!compiled_method) { - g_assert (jit_ex); - if (exc) { - *exc = (MonoObject*)jit_ex; - return NULL; - } else { - mono_raise_exception (jit_ex); - /* coverity[unreachable] */ - } + g_assert (!mono_error_ok (error)); + return NULL; } - compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE); + if (mono_llvm_only) { + ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL); + callee_gsharedvt = mini_jit_info_is_gsharedvt (ji); + if (callee_gsharedvt) + callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji))); + } + + if (!callee_gsharedvt) + compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE); } else { compiled_method = NULL; } - info = create_runtime_invoke_info (domain, method, compiled_method); + info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error); + if (!mono_error_ok (error)) + return NULL; mono_domain_lock (domain); info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info); @@ -2399,14 +2619,20 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec * We need this here because mono_marshal_get_runtime_invoke can place * the helper method in System.Object and not the target class. */ - if (exc) { - *exc = (MonoObject*)mono_runtime_class_init_full (info->vtable, FALSE); - if (*exc) - return NULL; - } else { - mono_runtime_class_init (info->vtable); + if (!mono_runtime_class_init_full (info->vtable, error)) { + if (exc) + *exc = (MonoObject*) mono_error_convert_to_exception (error); + return NULL; } + /* If coop is enabled, and the caller didn't ask for the exception to be caught separately, + we always catch the exception and propagate it through the MonoError */ + gboolean catchExcInMonoError = + (exc == NULL) && mono_threads_is_coop_enabled (); + MonoObject *invoke_exc = NULL; + if (catchExcInMonoError) + exc = &invoke_exc; + /* The wrappers expect this to be initialized to NULL */ if (exc) *exc = NULL; @@ -2419,15 +2645,16 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec int i, pindex; guint8 buf [512]; guint8 retval [256]; - gpointer rgctx; if (!dyn_runtime_invoke) { invoke = mono_marshal_get_runtime_invoke_dynamic (); - dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke); + dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error); + if (!mono_error_ok (error)) + return NULL; } /* Convert the arguments to the format expected by start_dyn_call () */ - args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer)); + args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer)); pindex = 0; if (sig->hasthis) args [pindex ++] = &obj; @@ -2442,16 +2669,14 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec args [pindex ++] = params [i]; } } - if (info->needs_rgctx) { - rgctx = mini_method_get_rgctx (method); - args [pindex ++] = &rgctx; - } //printf ("M: %s\n", mono_method_full_name (method, TRUE)); mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf)); dyn_runtime_invoke (buf, exc, info->compiled_method); + if (catchExcInMonoError && *exc != NULL) + mono_error_set_exception_instance (error, (MonoException*) *exc); mono_arch_finish_dyn_call (info->dyn_call_info, buf); @@ -2462,71 +2687,15 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec } #endif - runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke; - - if (info->wrapper_arg) { - MonoMethodSignature *sig = mono_method_signature (method); - gpointer *args; - gpointer retval_ptr; - guint8 retval [256]; - gpointer *param_refs; - int i, pindex; - - /* - * Instead of invoking the method directly, we invoke a gsharedvt out wrapper. - * The advantage of this is the gsharedvt out wrappers have a reduced set of - * signatures, so we only have to generate runtime invoke wrappers for these - * signatures. - */ - args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer)); - param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer)); - pindex = 0; - /* - * The runtime invoke wrappers expects pointers to primitive types, so have to - * use indirections. - */ - if (sig->hasthis) - args [pindex ++] = &obj; - if (sig->ret->type != MONO_TYPE_VOID) { - retval_ptr = (gpointer)&retval; - args [pindex ++] = &retval_ptr; - } - for (i = 0; i < sig->param_count; ++i) { - MonoType *t = sig->params [i]; - - if (MONO_TYPE_IS_REFERENCE (t)) { - param_refs [i] = params [i]; - params [i] = &(param_refs [i]); - } - args [pindex ++] = ¶ms [i]; - } - /* The gsharedvt out wrapper has an extra argument which contains the method to call */ - args [pindex ++] = &info->wrapper_arg; - runtime_invoke (NULL, args, exc, info->compiled_method); - - if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class) - return mono_value_box (domain, info->ret_box_class, retval); - else - return *(MonoObject**)retval; - } + if (mono_llvm_only) + return mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error); - // FIXME: Cache this - if (info->needs_rgctx) { - MonoMethodSignature *sig = mono_method_signature (method); - gpointer rgctx; - gpointer *args; - int i, pindex; + runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke; - args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer)); - pindex = 0; - rgctx = mini_method_get_rgctx (method); - for (i = 0; i < sig->param_count; ++i) - args [pindex ++] = params [i]; - args [pindex ++] = &rgctx; - return runtime_invoke ((MonoObject *)obj, args, exc, info->compiled_method); - } else { - return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method); - } + MonoObject *result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method); + if (catchExcInMonoError && *exc != NULL) + mono_error_set_exception_instance (error, (MonoException*) *exc); + return result; } typedef struct { @@ -2610,14 +2779,14 @@ mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method) } /* - * A version of the imt thunk used for generic virtual methods. + * A version of the imt thunk used for generic virtual/variant iface methods. * Unlikely a normal imt thunk, its possible that IMT_METHOD is not found * in the search table. The original JIT code had a 'fallback' trampoline it could * call, but we can't do that, so we just return NULL, and the compiled code * will handle it. */ static gpointer -mono_llvmonly_generic_virtual_imt_thunk (gpointer *arg, MonoMethod *imt_method) +mono_llvmonly_fallback_imt_thunk (gpointer *arg, MonoMethod *imt_method) { int i = 0; @@ -2705,8 +2874,8 @@ mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTChec res [0] = mono_llvmonly_imt_thunk; break; } - if (virtual_generic) - res [0] = mono_llvmonly_generic_virtual_imt_thunk; + if (virtual_generic || fail_tramp) + res [0] = mono_llvmonly_fallback_imt_thunk; res [1] = buf; return res; @@ -2980,6 +3149,48 @@ mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index) return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index)); } +static gboolean +is_callee_gsharedvt_variable (gpointer addr) +{ + MonoJitInfo *ji; + gboolean callee_gsharedvt; + + ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL); + g_assert (ji); + callee_gsharedvt = mini_jit_info_is_gsharedvt (ji); + if (callee_gsharedvt) + callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji))); + return callee_gsharedvt; +} + +gpointer +mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr) +{ + gpointer arg = NULL; + + if (mono_method_needs_static_rgctx_invoke (method, FALSE)) + arg = mini_method_get_rgctx (method); + + /* + * Avoid adding gsharedvt in wrappers since they might not exist if + * this delegate is called through a gsharedvt delegate invoke wrapper. + * Instead, encode that the method is gsharedvt in del->extra_arg, + * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this. + */ + if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) { + g_assert ((((mgreg_t)arg) & 1) == 0); + arg = (gpointer)(((mgreg_t)arg) | 1); + } + return arg; +} + +void +mini_init_delegate (MonoDelegate *del) +{ + if (mono_llvm_only) + del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr); +} + gpointer mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method) { @@ -2999,7 +3210,7 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE; load_imt_reg = is_virtual_generic || is_interface; - if (is_interface && !is_virtual_generic) + if (is_interface) offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P; else offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P)); @@ -3044,6 +3255,75 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met return cache [idx]; } +/** + * mini_parse_debug_option: + * @option: The option to parse. + * + * Parses debug options for the mono runtime. The options are the same as for + * the MONO_DEBUG environment variable. + * + */ +gboolean +mini_parse_debug_option (const char *option) +{ + if (!strcmp (option, "handle-sigint")) + debug_options.handle_sigint = TRUE; + else if (!strcmp (option, "keep-delegates")) + debug_options.keep_delegates = TRUE; + else if (!strcmp (option, "reverse-pinvoke-exceptions")) + debug_options.reverse_pinvoke_exceptions = TRUE; + else if (!strcmp (option, "collect-pagefault-stats")) + debug_options.collect_pagefault_stats = TRUE; + else if (!strcmp (option, "break-on-unverified")) + debug_options.break_on_unverified = TRUE; + else if (!strcmp (option, "no-gdb-backtrace")) + debug_options.no_gdb_backtrace = TRUE; + else if (!strcmp (option, "suspend-on-sigsegv")) + debug_options.suspend_on_sigsegv = TRUE; + else if (!strcmp (option, "suspend-on-exception")) + debug_options.suspend_on_exception = TRUE; + else if (!strcmp (option, "suspend-on-unhandled")) + debug_options.suspend_on_unhandled = TRUE; + else if (!strcmp (option, "dont-free-domains")) + mono_dont_free_domains = TRUE; + else if (!strcmp (option, "dyn-runtime-invoke")) + debug_options.dyn_runtime_invoke = TRUE; + else if (!strcmp (option, "gdb")) + debug_options.gdb = TRUE; + else if (!strcmp (option, "explicit-null-checks")) + debug_options.explicit_null_checks = TRUE; + else if (!strcmp (option, "gen-seq-points")) + debug_options.gen_sdb_seq_points = TRUE; + else if (!strcmp (option, "gen-compact-seq-points")) + debug_options.gen_seq_points_compact_data = TRUE; + else if (!strcmp (option, "single-imm-size")) + debug_options.single_imm_size = TRUE; + else if (!strcmp (option, "init-stacks")) + debug_options.init_stacks = TRUE; + else if (!strcmp (option, "casts")) + debug_options.better_cast_details = TRUE; + else if (!strcmp (option, "soft-breakpoints")) + debug_options.soft_breakpoints = TRUE; + else if (!strcmp (option, "check-pinvoke-callconv")) + debug_options.check_pinvoke_callconv = TRUE; + else if (!strcmp (option, "arm-use-fallback-tls")) + debug_options.arm_use_fallback_tls = TRUE; + else if (!strcmp (option, "debug-domain-unload")) + mono_enable_debug_domain_unload (TRUE); + else if (!strcmp (option, "partial-sharing")) + mono_set_partial_sharing_supported (TRUE); + else if (!strcmp (option, "align-small-structs")) + mono_align_small_structs = TRUE; + else if (!strcmp (option, "native-debugger-break")) + debug_options.native_debugger_break = TRUE; + else if (!strcmp (option, "disable_omit_fp")) + debug_options.disable_omit_fp = TRUE; + else + return FALSE; + + return TRUE; +} + static void mini_parse_debug_options (void) { @@ -3058,57 +3338,7 @@ mini_parse_debug_options (void) for (ptr = args; ptr && *ptr; ptr++) { const char *arg = *ptr; - if (!strcmp (arg, "handle-sigint")) - debug_options.handle_sigint = TRUE; - else if (!strcmp (arg, "keep-delegates")) - debug_options.keep_delegates = TRUE; - else if (!strcmp (arg, "reverse-pinvoke-exceptions")) - debug_options.reverse_pinvoke_exceptions = TRUE; - else if (!strcmp (arg, "collect-pagefault-stats")) - debug_options.collect_pagefault_stats = TRUE; - else if (!strcmp (arg, "break-on-unverified")) - debug_options.break_on_unverified = TRUE; - else if (!strcmp (arg, "no-gdb-backtrace")) - debug_options.no_gdb_backtrace = TRUE; - else if (!strcmp (arg, "suspend-on-sigsegv")) - debug_options.suspend_on_sigsegv = TRUE; - else if (!strcmp (arg, "suspend-on-exception")) - debug_options.suspend_on_exception = TRUE; - else if (!strcmp (arg, "suspend-on-unhandled")) - debug_options.suspend_on_unhandled = TRUE; - else if (!strcmp (arg, "dont-free-domains")) - mono_dont_free_domains = TRUE; - else if (!strcmp (arg, "dyn-runtime-invoke")) - debug_options.dyn_runtime_invoke = TRUE; - else if (!strcmp (arg, "gdb")) - debug_options.gdb = TRUE; - else if (!strcmp (arg, "explicit-null-checks")) - debug_options.explicit_null_checks = TRUE; - else if (!strcmp (arg, "gen-seq-points")) - debug_options.gen_sdb_seq_points = TRUE; - else if (!strcmp (arg, "gen-compact-seq-points")) - debug_options.gen_seq_points_compact_data = TRUE; - else if (!strcmp (arg, "single-imm-size")) - debug_options.single_imm_size = TRUE; - else if (!strcmp (arg, "init-stacks")) - debug_options.init_stacks = TRUE; - else if (!strcmp (arg, "casts")) - debug_options.better_cast_details = TRUE; - else if (!strcmp (arg, "soft-breakpoints")) - debug_options.soft_breakpoints = TRUE; - else if (!strcmp (arg, "check-pinvoke-callconv")) - debug_options.check_pinvoke_callconv = TRUE; - else if (!strcmp (arg, "arm-use-fallback-tls")) - debug_options.arm_use_fallback_tls = TRUE; - else if (!strcmp (arg, "debug-domain-unload")) - mono_enable_debug_domain_unload (TRUE); - else if (!strcmp (arg, "partial-sharing")) - mono_set_partial_sharing_supported (TRUE); - else if (!strcmp (arg, "align-small-structs")) - mono_align_small_structs = TRUE; - else if (!strcmp (arg, "native-debugger-break")) - debug_options.native_debugger_break = TRUE; - else { + if (!mini_parse_debug_option (arg)) { fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg); fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'gen-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n"); exit (1); @@ -3169,6 +3399,43 @@ register_jit_stats (void) mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot); mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm); mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm); + mono_counters_register ("JIT/method-to-IR (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir); + mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses); + 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); + mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts); + mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop); + mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops); + mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches); + mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs); + mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce); + mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis); + mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion); + mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering); + mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info); + mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops); + mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints); + mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute); + mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop); + mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce); + mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal); + mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove); + mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2); + mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2); + mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2); + mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2); + mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts); + mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts); + mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2); + mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness); + mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan); + mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars); + mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars); + mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3); + mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3); + mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen); + mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info); + mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map); + mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info); mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time); mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks); mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks); @@ -3259,6 +3526,12 @@ runtime_invoke_info_free (gpointer value) g_free (info); } +static void +free_jit_callee_list (gpointer key, gpointer value, gpointer user_data) +{ + g_slist_free (value); +} + static void mini_free_jit_domain_info (MonoDomain *domain) { @@ -3289,6 +3562,10 @@ mini_free_jit_domain_info (MonoDomain *domain) mono_debugger_agent_free_domain_info (domain); if (info->gsharedvt_arg_tramp_hash) g_hash_table_destroy (info->gsharedvt_arg_tramp_hash); + if (info->llvm_jit_callees) { + g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL); + g_hash_table_destroy (info->llvm_jit_callees); + } #ifdef ENABLE_LLVM mono_llvm_free_domain_info (domain); #endif @@ -3337,6 +3614,7 @@ mini_llvm_init (void) MonoDomain * mini_init (const char *filename, const char *runtime_version) { + MonoError error; MonoDomain *domain; MonoRuntimeCallbacks callbacks; MonoThreadInfoRuntimeCallbacks ticallbacks; @@ -3391,10 +3669,20 @@ mini_init (const char *filename, const char *runtime_version) callbacks.debug_log = mono_debugger_agent_debug_log; callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled; callbacks.tls_key_supported = mini_tls_key_supported; - callbacks.get_vtable_trampoline = mini_get_vtable_trampoline; callbacks.get_imt_trampoline = mini_get_imt_trampoline; callbacks.imt_entry_inited = mini_imt_entry_inited; + callbacks.init_delegate = mini_init_delegate; +#define JIT_INVOKE_WORKS +#ifdef JIT_INVOKE_WORKS + callbacks.runtime_invoke = mono_jit_runtime_invoke; +#endif +#define JIT_TRAMPOLINES_WORK +#ifdef JIT_TRAMPOLINES_WORK + callbacks.compile_method = mono_jit_compile_method; + callbacks.create_jump_trampoline = mono_create_jump_trampoline; + callbacks.create_jit_trampoline = mono_create_jit_trampoline; +#endif mono_install_callbacks (&callbacks); @@ -3464,22 +3752,14 @@ mini_init (const char *filename, const char *runtime_version) #endif mono_threads_install_cleanup (mini_thread_cleanup); -#define JIT_TRAMPOLINES_WORK #ifdef JIT_TRAMPOLINES_WORK - mono_install_compile_method (mono_jit_compile_method); mono_install_free_method (mono_jit_free_method); - mono_install_trampoline (mono_create_jit_trampoline); - mono_install_jump_trampoline (mono_create_jump_trampoline); #ifndef DISABLE_REMOTING mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline); #endif mono_install_delegate_trampoline (mono_create_delegate_trampoline); mono_install_create_domain_hook (mini_create_jit_domain_info); mono_install_free_domain_hook (mini_free_jit_domain_info); -#endif -#define JIT_INVOKE_WORKS -#ifdef JIT_INVOKE_WORKS - mono_install_runtime_invoke (mono_jit_runtime_invoke); #endif mono_install_get_cached_class_info (mono_aot_get_cached_class_info); mono_install_get_class_from_name (mono_aot_get_class_from_name); @@ -3557,7 +3837,8 @@ mini_init (const char *filename, const char *runtime_version) #define JIT_RUNTIME_WORKS #ifdef JIT_RUNTIME_WORKS mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup); - mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb); + mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error); + mono_error_assert_ok (&error); mono_thread_attach (domain); #endif @@ -3596,8 +3877,8 @@ register_icalls (void) register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE); register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE); register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE); - register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE); - register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE); + register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr ptr", TRUE); + register_icall (mono_jit_thread_detach, "mono_jit_thread_detach", "void ptr ptr", TRUE); register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE); register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE); @@ -3606,7 +3887,7 @@ register_icalls (void) register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE); register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE); register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE); - register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", FALSE); + register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE); #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED) register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE); @@ -3620,7 +3901,6 @@ register_icalls (void) register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE); register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE); register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE); - register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE); #ifndef DISABLE_REMOTING register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE); register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE); @@ -3770,11 +4050,11 @@ register_icalls (void) register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE); register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE); register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE); - register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE); - register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE); + register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE); + register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE); register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE); - register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE); - register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE); + register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE); + register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE); register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE); register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE); register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE); @@ -3809,7 +4089,8 @@ register_icalls (void) register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE); register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE); - register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE); + register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE); + register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE); register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr"); register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr"); @@ -3817,9 +4098,15 @@ register_icalls (void) register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr"); /* This needs a wrapper so it can have a preserveall cconv */ register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE); - register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE); - register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE); + register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE); + register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE); register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE); + register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE); + + register_icall_with_wrapper (mono_monitor_enter, "mono_monitor_enter", "void obj"); + register_icall_with_wrapper (mono_monitor_enter_v4, "mono_monitor_enter_v4", "void obj ptr"); + register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj"); + register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr"); #ifdef TARGET_IOS register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE); @@ -4019,7 +4306,13 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data) printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image)); for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { - method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL); + MonoError error; + + method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); + if (!method) { + mono_error_cleanup (&error); /* FIXME don't swallow the error */ + continue; + } if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) continue; if (method->is_generic || method->klass->generic_container) @@ -4033,7 +4326,7 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data) } mono_compile_method (method); if (strcmp (method->name, "Finalize") == 0) { - invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE); + invoke = mono_marshal_get_runtime_invoke (method, FALSE); mono_compile_method (invoke); } #ifndef DISABLE_REMOTING