void foo_ref_arg (string s);
}
+ interface IConstrained<T3> {
+ void foo_gsharedvt_arg (T3 s);
+ }
+
static object constrained_res;
struct ConsStruct : IConstrained {
}
}
+ struct ConsStruct<T> : IConstrained<T> {
+ public void foo_gsharedvt_arg (T s) {
+ constrained_res = s;
+ }
+ }
+
interface IFaceConstrained {
void constrained_void_iface_call<T, T2>(T t, T2 t2) where T2 : IConstrained;
void constrained_void_iface_call_ref_arg<T, T2>(T t, T2 t2) where T2 : IConstrained;
+ void constrained_void_iface_call_gsharedvt_arg<T, T2, T3>(T t, T2 t2, T3 t3) where T2 : IConstrained<T>;
}
class ClassConstrained : IFaceConstrained {
public void constrained_void_iface_call_ref_arg<T, T2>(T t, T2 t2) where T2 : IConstrained {
t2.foo_ref_arg ("A");
}
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public void constrained_void_iface_call_gsharedvt_arg<T, T2, T3>(T t, T2 t2, T3 t3) where T2 : IConstrained<T> {
+ t2.foo_gsharedvt_arg (t);
+ }
}
public static int test_0_constrained_void_iface_call () {
return 0;
}
+ public static int test_0_constraine_void_iface_call_gsharedvt_arg () {
+ // This tests constrained calls through interfaces with one gsharedvt arg, like IComparable<T>.CompareTo ()
+ IFaceConstrained c = new ClassConstrained ();
+
+ var s = new ConsStruct<int> ();
+ constrained_res = null;
+ c.constrained_void_iface_call_gsharedvt_arg<int, ConsStruct<int>, int> (42, s, 55);
+ if (!(constrained_res is int) || ((int)constrained_res) != 42)
+ return 1;
+
+ var s2 = new ConsStruct<string> ();
+ constrained_res = null;
+ c.constrained_void_iface_call_gsharedvt_arg<string, ConsStruct<string>, int> ("A", s2, 55);
+ if (!(constrained_res is string) || ((string)constrained_res) != "A")
+ return 2;
+
+ return 0;
+ }
+
public static async Task<T> FooAsync<T> (int i, int j) {
Task<int> t = new Task<int> (delegate () { return 42; });
var response = await t;
MonoMethod *m;
int vt_slot;
+ if (klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+ mono_raise_exception (mono_get_exception_execution_engine ("Not yet supported."));
+
/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (klass->vtable);
* the arguments to the method in the format used by mono_runtime_invoke ().
*/
MonoObject*
-mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *args)
+mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
{
MonoMethod *m;
gpointer this_arg;
+ gpointer new_args [16];
m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
+ if (args && deref_arg) {
+ new_args [0] = *(gpointer*)args [0];
+ args = new_args;
+ }
return mono_runtime_invoke (m, this_arg, args, NULL);
}
mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache);
MonoObject*
-mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *args) MONO_INTERNAL;
+mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args) MONO_INTERNAL;
void mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass) MONO_INTERNAL;
/* The 'Own method' case below */
} else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) &&
(MONO_TYPE_IS_VOID (fsig->ret) || fsig->ret->type == MONO_TYPE_I4 || fsig->ret->type == MONO_TYPE_BOOLEAN || fsig->ret->type == MONO_TYPE_STRING) &&
- (fsig->param_count == 0 || (fsig->param_count == 1 && MONO_TYPE_IS_REFERENCE (fsig->params [0])))) {
+ (fsig->param_count == 0 || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
MonoInst *args [16];
/*
- * This case handles calls to object:ToString()/Equals()/GetHashCode(), plus some simple interface calls enough to support
- * AsyncTaskMethodBuilder.
+ * This case handles calls to
+ * - object:ToString()/Equals()/GetHashCode(),
+ * - System.IComparable<T>:CompareTo()
+ * - System.IEquatable<T>:Equals ()
+ * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
*/
args [0] = sp [0];
- EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+ if (mono_method_check_context_used (cmethod))
+ args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
+ else
+ EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
if (fsig->param_count) {
ins->dreg = alloc_preg (cfg);
ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
MONO_ADD_INS (cfg->cbb, ins);
- args [3] = ins;
+ args [4] = ins;
+
+ if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
+ int addr_reg;
+
+ args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
- EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [3]->dreg, 0, sp [1]->dreg);
+ EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
+ addr_reg = ins->dreg;
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
+ } else {
+ EMIT_NEW_ICONST (cfg, args [3], 0);
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
+ }
} else {
EMIT_NEW_ICONST (cfg, args [3], 0);
+ EMIT_NEW_ICONST (cfg, args [4], 0);
}
ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
emit_widen = FALSE;
register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
- register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr", TRUE);
+ register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", TRUE);
register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);