diff --git a/src/mono/mono/mini/gshared.cs b/src/mono/mono/mini/gshared.cs index c2903f0708bd0..65693924c05ce 100644 --- a/src/mono/mono/mini/gshared.cs +++ b/src/mono/mono/mini/gshared.cs @@ -1472,15 +1472,16 @@ public static int test_0_nullable_unbox () { interface IConstrained { void foo (); - void foo_ref_arg (string s); + void foo_ref_arg (string s, string s2); } interface IConstrained { - void foo_gsharedvt_arg (T3 s); + void foo_gsharedvt_arg (T3 s, T3 s2); T3 foo_gsharedvt_ret (T3 s); } static object constrained_res; + static object constrained_res2; struct ConsStruct : IConstrained { public int i; @@ -1489,8 +1490,8 @@ public void foo () { constrained_res = i; } - public void foo_ref_arg (string s) { - constrained_res = s == "A" ? 42 : 0; + public void foo_ref_arg (string s, string s2) { + constrained_res = (s == "A" && s2 == "B") ? 42 : 0; } } @@ -1501,14 +1502,15 @@ public void foo () { constrained_res = i; } - public void foo_ref_arg (string s) { - constrained_res = s == "A" ? 43 : 0; + public void foo_ref_arg (string s, string s2) { + constrained_res = (s == "A" && s2 == "B") ? 43 : 0; } } struct ConsStruct : IConstrained { - public void foo_gsharedvt_arg (T s) { + public void foo_gsharedvt_arg (T s, T s2) { constrained_res = s; + constrained_res2 = s2; } public T foo_gsharedvt_ret (T s) { @@ -1521,7 +1523,7 @@ public void foo () { throw new Exception (); } - public void foo_ref_arg (string s) { + public void foo_ref_arg (string s, string s2) { } } @@ -1541,12 +1543,12 @@ public void constrained_void_iface_call(T t, T2 t2) where T2 : IConstrain [MethodImplAttribute (MethodImplOptions.NoInlining)] public void constrained_void_iface_call_ref_arg(T t, T2 t2) where T2 : IConstrained { - t2.foo_ref_arg ("A"); + t2.foo_ref_arg ("A", "B"); } [MethodImplAttribute (MethodImplOptions.NoInlining)] public void constrained_void_iface_call_gsharedvt_arg(T t, T2 t2, T3 t3) where T2 : IConstrained { - t2.foo_gsharedvt_arg (t); + t2.foo_gsharedvt_arg (t, t); } [MethodImplAttribute (MethodImplOptions.NoInlining)] @@ -1616,6 +1618,8 @@ public static int test_0_constrained_void_iface_call_gsharedvt_arg () { c.constrained_void_iface_call_gsharedvt_arg, int> ("A", s2, 55); if (!(constrained_res is string) || ((string)constrained_res) != "A") return 2; + if (!(constrained_res2 is string) || ((string)constrained_res2) != "A") + return 3; return 0; } diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index 40e0110fbb58d..98290fde4e160 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -1396,7 +1396,7 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k * the arguments to the method in the format used by mono_runtime_invoke_checked (). */ MonoObject* -mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args) +mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, guint8 *deref_args, gpointer *args) { ERROR_DECL (error); MonoObject *o; @@ -1424,8 +1424,15 @@ mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *kl if (!m) return NULL; - if (args && deref_arg) { - new_args [0] = *(gpointer*)args [0]; + if (deref_args) { + /* Have to deref gsharedvt ref arguments since the runtime invoke expects it */ + MonoMethodSignature *fsig = mono_method_signature_internal (m); + g_assert (fsig->param_count < 16); + memcpy (new_args, args, fsig->param_count * sizeof (gpointer)); + for (int i = 0; i < fsig->param_count; ++i) { + if (deref_args [i]) + new_args [i] = *(gpointer*)new_args [i]; + } args = new_args; } if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) { diff --git a/src/mono/mono/mini/jit-icalls.h b/src/mono/mono/mini/jit-icalls.h index 86b96a7612f52..646e888b471f8 100644 --- a/src/mono/mono/mini/jit-icalls.h +++ b/src/mono/mono/mini/jit-icalls.h @@ -203,7 +203,7 @@ ICALL_EXPORT void ves_icall_mono_delegate_ctor_interp (MonoObject *this_obj, MonoObject *target, gpointer addr); -ICALL_EXPORT MonoObject* mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args); +ICALL_EXPORT MonoObject* mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, guint8 *deref_args, gpointer *args); ICALL_EXPORT void mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 3bb0364cee139..130803f93d1f3 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -3676,13 +3676,10 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe if (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1)) { supported = TRUE; } else { - /* Allow scalar parameters and a gsharedvt first parameter */ - supported = MONO_TYPE_IS_PRIMITIVE (fsig->params [0]) || MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]); - if (supported) { - for (int i = 1; i < fsig->param_count; ++i) { - if (!(fsig->params [i]->byref || MONO_TYPE_IS_PRIMITIVE (fsig->params [i]) || MONO_TYPE_IS_REFERENCE (fsig->params [i]) || MONO_TYPE_ISSTRUCT (fsig->params [i]))) - supported = FALSE; - } + supported = TRUE; + for (int i = 0; i < fsig->param_count; ++i) { + if (!(fsig->params [i]->byref || MONO_TYPE_IS_PRIMITIVE (fsig->params [i]) || MONO_TYPE_IS_REFERENCE (fsig->params [i]) || MONO_TYPE_ISSTRUCT (fsig->params [i]) || mini_is_gsharedvt_type (fsig->params [i]))) + supported = FALSE; } } } @@ -3703,7 +3700,22 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */ if (fsig->hasthis && fsig->param_count) { - /* Call mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args) */ + /* Call mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean *deref_args, gpointer *args) */ + gboolean has_gsharedvt = FALSE; + for (int i = 0; i < fsig->param_count; ++i) { + if (mini_is_gsharedvt_type (fsig->params [i])) + has_gsharedvt = TRUE; + } + /* Pass an array of bools which signal whenever the corresponding argument is a gsharedvt ref type */ + if (has_gsharedvt) { + MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM); + ins->dreg = alloc_preg (cfg); + ins->inst_imm = fsig->param_count; + MONO_ADD_INS (cfg->cbb, ins); + args [3] = ins; + } else { + EMIT_NEW_PCONST (cfg, args [3], 0); + } /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */ MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM); ins->dreg = alloc_preg (cfg); @@ -3711,21 +3723,21 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe MONO_ADD_INS (cfg->cbb, ins); args [4] = ins; - /* Only the first argument is allowed to be gsharedvt */ - /* args [3] = deref_arg */ - if (mini_is_gsharedvt_type (fsig->params [0])) { - int deref_arg_reg; - ins = mini_emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type_internal (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE); - deref_arg_reg = alloc_preg (cfg); - /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */ - EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1); - } else { - EMIT_NEW_ICONST (cfg, args [3], 0); - } - for (int i = 0; i < fsig->param_count; ++i) { int addr_reg; + if (mini_is_gsharedvt_type (fsig->params [i])) { + MonoInst *is_deref; + int deref_arg_reg; + ins = mini_emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type_internal (fsig->params [i]), MONO_RGCTX_INFO_CLASS_BOX_TYPE); + deref_arg_reg = alloc_preg (cfg); + /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */ + EMIT_NEW_BIALU_IMM (cfg, is_deref, OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, i, is_deref->dreg); + } else if (has_gsharedvt) { + MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, args [3]->dreg, i, 0); + } + if (mini_is_gsharedvt_type (fsig->params [i]) || MONO_TYPE_IS_PRIMITIVE (fsig->params [i]) || MONO_TYPE_ISSTRUCT (fsig->params [i])) { EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [i + 1]->dreg, fsig->params [i]); addr_reg = ins->dreg;