Skip to content

Commit

Permalink
[mono] Remove some of the restrictions on constrained calls from
Browse files Browse the repository at this point in the history
gsharedvt methods.

Fixes #58204.
  • Loading branch information
vargaz committed Sep 16, 2021
1 parent d2cef2f commit ecce350
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 34 deletions.
24 changes: 14 additions & 10 deletions src/mono/mono/mini/gshared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T3> {
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;
Expand All @@ -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;
}
}

Expand All @@ -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<T> : IConstrained<T> {
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) {
Expand All @@ -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) {
}
}

Expand All @@ -1541,12 +1543,12 @@ public void constrained_void_iface_call<T, T2>(T t, T2 t2) where T2 : IConstrain

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public void constrained_void_iface_call_ref_arg<T, T2>(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, T2, T3>(T t, T2 t2, T3 t3) where T2 : IConstrained<T> {
t2.foo_gsharedvt_arg (t);
t2.foo_gsharedvt_arg (t, t);
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
Expand Down Expand Up @@ -1616,6 +1618,8 @@ public static int test_0_constrained_void_iface_call_gsharedvt_arg () {
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;
if (!(constrained_res2 is string) || ((string)constrained_res2) != "A")
return 3;

return 0;
}
Expand Down
13 changes: 10 additions & 3 deletions src/mono/mono/mini/jit-icalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/jit-icalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
52 changes: 32 additions & 20 deletions src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand All @@ -3703,29 +3700,44 @@ 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);
ins->inst_imm = fsig->param_count * sizeof (target_mgreg_t);
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;
Expand Down

0 comments on commit ecce350

Please sign in to comment.