}
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");
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;
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 ();
}
info = g_new0 (RuntimeInvokeInfo, 1);
info->compiled_method = compiled_method;
+ info->sig = mono_method_signature (method);
invoke = mono_marshal_get_runtime_invoke (method, FALSE);
info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
#ifndef ENABLE_GSHAREDVT
g_assert_not_reached ();
#endif
+ 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->gsharedvt_invoke = TRUE;
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);
/* 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->gsharedvt_invoke = TRUE;
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);
return info;
}
+static MonoObject*
+mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc)
+{
+ 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;
+
+ 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 (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
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)
}
#endif
- runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
-
- if (mono_llvm_only) {
- MonoMethodSignature *sig = mono_method_signature (method);
- gpointer *args;
- gpointer retval_ptr;
- guint8 retval [256];
- gpointer *param_refs;
- int i, pindex;
-
- 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 (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 (mono_llvm_only)
+ return mono_llvmonly_runtime_invoke (method, info, obj, params, 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;
- }
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_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;
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;
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;
+}
+
+void
+mini_init_delegate (MonoDelegate *del)
+{
+ if (mono_llvm_only) {
+ MonoMethod *method = del->method;
+
+ if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+ del->rgctx = 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->rgctx,
+ * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
+ */
+ if (is_callee_gsharedvt_variable (del->method_ptr)) {
+ g_assert ((((mgreg_t)del->rgctx) & 1) == 0);
+ del->rgctx = (gpointer)(((mgreg_t)del->rgctx) | 1);
+ }
+ }
+}
+
gpointer
mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
{
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 *arg)
+mini_parse_debug_option (const char *option)
{
- if (!strcmp (arg, "handle-sigint"))
+ if (!strcmp (option, "handle-sigint"))
debug_options.handle_sigint = TRUE;
- else if (!strcmp (arg, "keep-delegates"))
+ else if (!strcmp (option, "keep-delegates"))
debug_options.keep_delegates = TRUE;
- else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
+ else if (!strcmp (option, "reverse-pinvoke-exceptions"))
debug_options.reverse_pinvoke_exceptions = TRUE;
- else if (!strcmp (arg, "collect-pagefault-stats"))
+ else if (!strcmp (option, "collect-pagefault-stats"))
debug_options.collect_pagefault_stats = TRUE;
- else if (!strcmp (arg, "break-on-unverified"))
+ else if (!strcmp (option, "break-on-unverified"))
debug_options.break_on_unverified = TRUE;
- else if (!strcmp (arg, "no-gdb-backtrace"))
+ else if (!strcmp (option, "no-gdb-backtrace"))
debug_options.no_gdb_backtrace = TRUE;
- else if (!strcmp (arg, "suspend-on-sigsegv"))
+ else if (!strcmp (option, "suspend-on-sigsegv"))
debug_options.suspend_on_sigsegv = TRUE;
- else if (!strcmp (arg, "suspend-on-exception"))
+ else if (!strcmp (option, "suspend-on-exception"))
debug_options.suspend_on_exception = TRUE;
- else if (!strcmp (arg, "suspend-on-unhandled"))
+ else if (!strcmp (option, "suspend-on-unhandled"))
debug_options.suspend_on_unhandled = TRUE;
- else if (!strcmp (arg, "dont-free-domains"))
+ else if (!strcmp (option, "dont-free-domains"))
mono_dont_free_domains = TRUE;
- else if (!strcmp (arg, "dyn-runtime-invoke"))
+ else if (!strcmp (option, "dyn-runtime-invoke"))
debug_options.dyn_runtime_invoke = TRUE;
- else if (!strcmp (arg, "gdb"))
+ else if (!strcmp (option, "gdb"))
debug_options.gdb = TRUE;
- else if (!strcmp (arg, "explicit-null-checks"))
+ else if (!strcmp (option, "explicit-null-checks"))
debug_options.explicit_null_checks = TRUE;
- else if (!strcmp (arg, "gen-seq-points"))
+ else if (!strcmp (option, "gen-seq-points"))
debug_options.gen_sdb_seq_points = TRUE;
- else if (!strcmp (arg, "gen-compact-seq-points"))
+ else if (!strcmp (option, "gen-compact-seq-points"))
debug_options.gen_seq_points_compact_data = TRUE;
- else if (!strcmp (arg, "single-imm-size"))
+ else if (!strcmp (option, "single-imm-size"))
debug_options.single_imm_size = TRUE;
- else if (!strcmp (arg, "init-stacks"))
+ else if (!strcmp (option, "init-stacks"))
debug_options.init_stacks = TRUE;
- else if (!strcmp (arg, "casts"))
+ else if (!strcmp (option, "casts"))
debug_options.better_cast_details = TRUE;
- else if (!strcmp (arg, "soft-breakpoints"))
+ else if (!strcmp (option, "soft-breakpoints"))
debug_options.soft_breakpoints = TRUE;
- else if (!strcmp (arg, "check-pinvoke-callconv"))
+ else if (!strcmp (option, "check-pinvoke-callconv"))
debug_options.check_pinvoke_callconv = TRUE;
- else if (!strcmp (arg, "arm-use-fallback-tls"))
+ else if (!strcmp (option, "arm-use-fallback-tls"))
debug_options.arm_use_fallback_tls = TRUE;
- else if (!strcmp (arg, "debug-domain-unload"))
+ else if (!strcmp (option, "debug-domain-unload"))
mono_enable_debug_domain_unload (TRUE);
- else if (!strcmp (arg, "partial-sharing"))
+ else if (!strcmp (option, "partial-sharing"))
mono_set_partial_sharing_supported (TRUE);
- else if (!strcmp (arg, "align-small-structs"))
+ else if (!strcmp (option, "align-small-structs"))
mono_align_small_structs = TRUE;
- else if (!strcmp (arg, "native-debugger-break"))
+ else if (!strcmp (option, "native-debugger-break"))
debug_options.native_debugger_break = TRUE;
else
return FALSE;
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;
mono_install_callbacks (&callbacks);
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_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 (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");
register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
+ register_icall_no_wrapper (mono_llvmonly_set_calling_assembly, "mono_llvmonly_set_calling_assembly", "void ptr");
+ register_icall_no_wrapper (mono_llvmonly_get_calling_assembly, "mono_llvmonly_get_calling_assembly", "object");
/* 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 object ptr", 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);
#ifdef TARGET_IOS
register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);