return 0;
}
+ public interface IFace<T> {
+ T return_t_iface (T t);
+ }
+
public class Parent<T> {
public virtual T return_t_vcall (T t) {
throw new Exception ();
}
}
- public class Child<T> : Parent<T> {
+ public class Child<T> : Parent<T>, IFace<T> {
public override T return_t_vcall (T t) {
return t;
}
+ public T return_t_iface (T t) {
+ return t;
+ }
}
[MethodImplAttribute (MethodImplOptions.NoInlining)]
return 0;
}
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ static T return_t_iface<T> (IFace<T> r, T t) {
+ return r.return_t_iface (t);
+ }
+
+ public static int test_0_iface_calls () {
+ if (return_t_iface (new Child<int> (), 2) != 2)
+ return 1;
+ if (return_t_iface (new Child<double> (), 2.0) != 2.0)
+ return 3;
+ return 0;
+ }
+
static KeyValuePair<T1, T2> make_kvp<T1, T2> (T1 t1, T2 t2) {
return new KeyValuePair<T1, T2> (t1, t2);
}
#ifdef MONO_ARCH_HAVE_IMT
static void
-emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
+emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
{
int method_reg;
if (imt_arg) {
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
} else if (cfg->compile_aot) {
- MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+ MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
} else {
MonoInst *ins;
MONO_INST_NEW (cfg, ins, OP_PCONST);
- ins->inst_p0 = call->method;
+ ins->inst_p0 = method;
ins->dreg = method_reg;
MONO_ADD_INS (cfg->cbb, ins);
}
if (imt_arg) {
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
} else if (cfg->compile_aot) {
- MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+ MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
} else {
MonoInst *ins;
MONO_INST_NEW (cfg, ins, OP_PCONST);
- ins->inst_p0 = call->method;
+ ins->inst_p0 = method;
ins->dreg = method_reg;
MONO_ADD_INS (cfg->cbb, ins);
}
return (MonoInst*)call;
}
+/* This is like calli, but we pass rgctx/imt arguments as well */
+static MonoInst*
+emit_gsharedvt_call (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoMethod *method, MonoInst *imt_arg, MonoInst *rgctx_arg)
+{
+ MonoCallInst *call;
+ int rgctx_reg = -1;
+
+ if (rgctx_arg) {
+ rgctx_reg = mono_alloc_preg (cfg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
+ }
+
+ call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
+
+ call->inst.sreg1 = addr->dreg;
+
+ if (imt_arg)
+ emit_imt_argument (cfg, call, method, imt_arg);
+
+ MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
+
+ if (rgctx_arg)
+ set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
+
+ return (MonoInst*)call;
+}
+
static MonoInst*
emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
static MonoInst*
#ifdef MONO_ARCH_HAVE_IMT
if (mono_use_imt) {
guint32 imt_slot = mono_method_get_imt_slot (method);
- emit_imt_argument (cfg, call, imt_arg);
+ emit_imt_argument (cfg, call, call->method, imt_arg);
slot_reg = vtable_reg;
call->inst.inst_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
}
#ifdef MONO_ARCH_HAVE_IMT
if (imt_arg) {
g_assert (mono_method_signature (method)->generic_param_count);
- emit_imt_argument (cfg, call, imt_arg);
+ emit_imt_argument (cfg, call, call->method, imt_arg);
}
#endif
}
MonoInst *addr;
if (virtual) {
- if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
- GSHAREDVT_FAILURE (*ip);
+ //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+ //GSHAREDVT_FAILURE (*ip);
// disable for possible remoting calls
if (fsig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))
GSHAREDVT_FAILURE (*ip);
else
addr = emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
- ins = mono_emit_calli (cfg, fsig, sp, addr, vtable_arg);
+ ins = emit_gsharedvt_call (cfg, fsig, sp, addr, cmethod, imt_arg, vtable_arg);
if (!MONO_TYPE_IS_VOID (fsig->ret))
*sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
gpointer addr;
MonoJitInfo *ji;
gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
+ gint32 vcall_offset;
g_assert (method->is_inflated);
else
addr = NULL;
+ if (virtual) {
+ /* Same as in mono_emit_method_call_full () */
+#ifndef MONO_ARCH_HAVE_IMT
+ NOT_IMPLEMENTED;
+#endif
+ if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ guint32 imt_slot = mono_method_get_imt_slot (method);
+ vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
+ } else {
+ vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
+ ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
+ }
+ } else {
+ vcall_offset = -1;
+ }
+
/*
* For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
* non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
mini_init_gsctx (context, &gsctx);
- info = mono_arch_get_gsharedvt_call_info (addr, method, gm, &gsctx, FALSE, virtual);
+ info = mono_arch_get_gsharedvt_call_info (addr, method, gm, &gsctx, FALSE, vcall_offset);
if (!tramp_addr) {
wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
// FIXME: This is just a workaround
if (caller_method == method) {
} else {
- info = mono_arch_get_gsharedvt_call_info (ji->code_start, method, ji->method, &gsctx, TRUE, FALSE);
+ info = mono_arch_get_gsharedvt_call_info (ji->code_start, method, ji->method, &gsctx, TRUE, -1);
if (!tramp_addr) {
wrapper = mono_marshal_get_gsharedvt_in_wrapper ();