Skip to content

Commit

Permalink
[jit] Use the right type when handling shared versions of RuntimeHelp…
Browse files Browse the repository at this point in the history
…ers.IsReferenceOrContainsReferences (). The previous version only worked by accident. (#5160)
  • Loading branch information
vargaz committed Jul 3, 2017
1 parent 7df3435 commit 3d531ba
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
21 changes: 21 additions & 0 deletions mono/mini/generics.cs
Expand Up @@ -1314,6 +1314,13 @@ class ThrowClass<T> where T: Exception {
return RuntimeHelpers.IsReferenceOrContainsReferences<T> ();
}

class IsRefClass<T> {
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public bool is_ref () {
return RuntimeHelpers.IsReferenceOrContainsReferences<T> ();
}
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static bool is_ref_or_contains_refs_gen_ref<T> () {
return RuntimeHelpers.IsReferenceOrContainsReferences<GenStruct<T>> ();
Expand Down Expand Up @@ -1343,6 +1350,12 @@ struct NoRefStruct {
int i;
}

struct AStruct3<T1, T2, T3> {
T1 t1;
T2 t2;
T3 t3;
}

public static int test_0_isreference_intrins () {
if (RuntimeHelpers.IsReferenceOrContainsReferences<int> ())
return 1;
Expand All @@ -1368,6 +1381,14 @@ struct NoRefStruct {
if (is_ref_or_contains_refs_gen_noref<string> ())
return 10;

// Complex type from shared class method
var c1 = new IsRefClass<AStruct3<int, int, int>> ();
if (c1.is_ref ())
return 11;
var c2 = new IsRefClass<AStruct3<string, int, int>> ();
if (!c2.is_ref ())
return 12;

return 0;
}
}
Expand Down
24 changes: 24 additions & 0 deletions mono/mini/gshared.cs
Expand Up @@ -1972,6 +1972,30 @@ void gsharedvt_try_at_offset_0<T> (ref T disposable)
gsharedvt_vphi (0);
return 0;
}

struct AStruct3<T1, T2, T3> {
T1 t1;
T2 t2;
T3 t3;
}

interface IFaceIsRef {
bool is_ref<T> ();
}

class ClassIsRef : IFaceIsRef {
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public bool is_ref<T> () {
return RuntimeHelpers.IsReferenceOrContainsReferences<T> ();
}
}

public static int test_0_isreference_intrins () {
IFaceIsRef iface = new ClassIsRef ();
Console.WriteLine ("X: " + iface.is_ref<AStruct3<int, int, int>> ());
Console.WriteLine ("X: " + iface.is_ref<AStruct3<string, int, int>> ());
return 0;
}
}

// #13191
Expand Down
14 changes: 10 additions & 4 deletions mono/mini/method-to-ir.c
Expand Up @@ -5407,11 +5407,15 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
g_assert (ctx);
g_assert (ctx->method_inst);
g_assert (ctx->method_inst->type_argc == 1);
MonoType *t = mini_get_underlying_type (ctx->method_inst->type_argv [0]);
MonoClass *klass = mono_class_from_mono_type (t);
MonoType *arg_type = ctx->method_inst->type_argv [0];
MonoType *t;
MonoClass *klass;

ins = NULL;

/* Resolve the argument class as possible so we can handle common cases fast */
t = mini_get_underlying_type (arg_type);
klass = mono_class_from_mono_type (t);
mono_class_init (klass);
if (MONO_TYPE_IS_REFERENCE (t))
EMIT_NEW_ICONST (cfg, ins, 1);
Expand All @@ -5424,10 +5428,12 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
else {
g_assert (cfg->gshared);

int context_used = mini_class_check_context_used (cfg, klass);
/* Have to use the original argument class here */
MonoClass *arg_class = mono_class_from_mono_type (arg_type);
int context_used = mini_class_check_context_used (cfg, arg_class);

/* This returns 1 or 2 */
MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, arg_class, MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
int dreg = alloc_ireg (cfg);
EMIT_NEW_BIALU_IMM (cfg, ins, OP_ISUB_IMM, dreg, info->dreg, 1);
}
Expand Down

0 comments on commit 3d531ba

Please sign in to comment.