Prechádzať zdrojové kódy

[jit] Use the right type when handling shared versions of RuntimeHelpers.IsReferenceOrContainsReferences (). The previous version only worked by accident. (#5160)

Zoltan Varga 8 rokov pred
rodič
commit
86ccab6997
3 zmenil súbory, kde vykonal 55 pridanie a 4 odobranie
  1. 21 0
      mono/mini/generics.cs
  2. 24 0
      mono/mini/gshared.cs
  3. 10 4
      mono/mini/method-to-ir.c

+ 21 - 0
mono/mini/generics.cs

@@ -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;
 	}
 }

+ 24 - 0
mono/mini/gshared.cs

@@ -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

+ 10 - 4
mono/mini/method-to-ir.c

@@ -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);
 			}