[jit] Use the right type when handling shared versions of RuntimeHelpers.IsReferenceO...
authorZoltan Varga <vargaz@gmail.com>
Sun, 2 Jul 2017 06:08:44 +0000 (02:08 -0400)
committerGitHub <noreply@github.com>
Sun, 2 Jul 2017 06:08:44 +0000 (02:08 -0400)
mono/mini/generics.cs
mono/mini/gshared.cs
mono/mini/method-to-ir.c

index e9b41a64e08ab33fe63924edf89aeec83d2b0b52..eafbd1c0e541c9187885ac412d98cdb863ae173e 100644 (file)
@@ -1314,6 +1314,13 @@ class Tests
                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>> ();
@@ -1343,6 +1350,12 @@ class Tests
                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;
@@ -1368,6 +1381,14 @@ class Tests
                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;
        }
 }
index 29943694c72fa7ccbf6bbc98256a040792325fd8..61402f7a4eca4f0314d21eb7918cf5e16ae02a00 100644 (file)
@@ -1972,6 +1972,30 @@ public class Tests
                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
index 7ae63f25aa29b516bb778a17f2df3867ad0832a3..9b602e10a6903e327d437aa218f6a97c46e9e118 100644 (file)
@@ -5055,11 +5055,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);
@@ -5072,10 +5076,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);
                        }