/* Must be domain neutral since there is only one copy */
opt |= MONO_OPT_SHARED;
- }
-
- if (method->dynamic)
- opt &= ~MONO_OPT_SHARED;
-
- /* These methods can become invalid when a domain is unloaded */
- if (method->klass->image != mono_get_corlib () || method->is_inflated)
+ } else {
+ /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
opt &= ~MONO_OPT_SHARED;
+ }
if (opt & MONO_OPT_SHARED)
target_domain = mono_get_root_domain ();
MonoClass *ret_box_class;
gboolean needs_rgctx;
MonoMethodSignature *sig;
+ gboolean gsharedvt_invoke;
gpointer *wrapper_arg;
} RuntimeInvokeInfo;
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;
- }
+ if (sig->ret->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (sig->ret)))
+ 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)
{
MonoMethod *invoke;
RuntimeInvokeInfo *info;
#ifndef ENABLE_GSHAREDVT
supported = FALSE;
#endif
-
- if (supported) {
+ if (supported && !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;
g_free (wrapper_sig);
info->compiled_method = mono_jit_compile_method (wrapper);
+ } else if (supported) {
+ /* 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->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);
+ g_free (wrapper_sig);
}
}
info->runtime_invoke = mono_jit_compile_method (invoke);
MonoDomain *domain = mono_domain_get ();
MonoJitDomainInfo *domain_info;
RuntimeInvokeInfo *info, *info2;
+ MonoJitInfo *ji = NULL;
+ gboolean callee_gsharedvt = FALSE;
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");
}
}
- 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)
+ 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);
mono_domain_lock (domain);
info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
- if (info->wrapper_arg) {
+ if (info->gsharedvt_invoke) {
MonoMethodSignature *sig = mono_method_signature (method);
gpointer *args;
gpointer retval_ptr;
guint8 retval [256];
- gpointer param_refs [256];
+ gpointer *param_refs;
int i, pindex;
/*
* 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
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]);
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);
+ return mono_value_box (domain, info->ret_box_class, retval);
else
return *(MonoObject**)retval;
}
/* Return what the real IMT thunk returns */
ftndesc = imt [info->slot];
func = ftndesc [0];
+
+ if (func == (IMTThunkFunc)mini_llvmonly_initial_imt_thunk)
+ /* Happens when the imt slot contains only a generic virtual method */
+ return NULL;
return func ((gpointer *)ftndesc [1], imt_method);
}
if (!item->is_equals || item->has_target_code)
continue;
vt_slot = item->value.vtable_slot;
- mono_init_vtable_slot_vt (vtable, vt_slot);
+ mono_init_vtable_slot (vtable, vt_slot);
}
/* Save the entries into an array */
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));
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_no_wrapper (mono_resolve_iface_call, "mono_resolve_iface_call", "ptr object int ptr ptr");
- register_icall_no_wrapper (mono_resolve_vcall, "mono_resolve_vcall", "ptr object int ptr ptr");
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 object int 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");
/* This needs a wrapper so it can have a preserveall cconv */
- register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr object int", FALSE);
+ 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_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);