diff --git a/src/coreclr/src/tools/Common/Compiler/TypeExtensions.cs b/src/coreclr/src/tools/Common/Compiler/TypeExtensions.cs index 89fd08f3dbab42..dd54a1387bdf9e 100644 --- a/src/coreclr/src/tools/Common/Compiler/TypeExtensions.cs +++ b/src/coreclr/src/tools/Common/Compiler/TypeExtensions.cs @@ -97,6 +97,19 @@ public static bool IsArrayAddressMethod(this MethodDesc method) return arrayMethod != null && arrayMethod.Kind == ArrayMethodKind.Address; } + + /// + /// Returns true if '' is one of the special methods on multidimensional array types (set, get, address). + /// + public static bool IsArrayMethod(this MethodDesc method) + { + var arrayMethod = method as ArrayMethod; + return arrayMethod != null && (arrayMethod.Kind == ArrayMethodKind.Address || + arrayMethod.Kind == ArrayMethodKind.Get || + arrayMethod.Kind == ArrayMethodKind.Set || + arrayMethod.Kind == ArrayMethodKind.Ctor); + } + /// /// Gets a value indicating whether this type has any generic virtual methods. /// diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs index 54b9849aed8cef..fd80e7e74a582a 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; @@ -441,11 +442,18 @@ public void EmitMethodSignature( // Owner type is needed for type specs to instantiating stubs or generics with signature variables still present if (!method.Method.OwningType.IsDefType && - ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0 || method.Method.OwningType.ContainsSignatureVariables()) - || method.Method.IsArrayAddressMethod()) + ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0 || method.Method.OwningType.ContainsSignatureVariables())) { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; } + else if (method.Method.IsArrayMethod()) + { + var memberRefMethod = method.Token.Module.GetMethod(MetadataTokens.EntityHandle((int)method.Token.Token)); + if (memberRefMethod.OwningType != method.Method.OwningType) + { + flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; + } + } EmitUInt(flags); if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) diff --git a/src/coreclr/tests/issues.targets b/src/coreclr/tests/issues.targets index e33de4df6132f4..ac5addebf4b3ba 100644 --- a/src/coreclr/tests/issues.targets +++ b/src/coreclr/tests/issues.targets @@ -920,9 +920,6 @@ https://github.com/dotnet/runtime/issues/38096 - - https://github.com/dotnet/runtime/issues/38260 - https://github.com/dotnet/runtime/issues/7597 @@ -959,9 +956,6 @@ https://github.com/dotnet/runtime/issues/38290 - - https://github.com/dotnet/runtime/issues/38260 - https://github.com/dotnet/runtime/issues/32728 diff --git a/src/tests/readytorun/crossgen2/Program.cs b/src/tests/readytorun/crossgen2/Program.cs index bd00957a758409..e2da7433754608 100644 --- a/src/tests/readytorun/crossgen2/Program.cs +++ b/src/tests/readytorun/crossgen2/Program.cs @@ -1626,6 +1626,145 @@ private static bool GenericLdtokenTest() return true; } + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool CheckArrayVal(ref T refVal, T testValue) where T:IEquatable + { + return refVal.Equals(testValue); + } + + struct SomeLargeStruct : IEquatable + { + public SomeLargeStruct(int _xVal) + { + x = _xVal; + y = 0; + z = 0; + w = 0; + } + public int x; + public int y; + public int z; + public int w; + + public bool Equals(SomeLargeStruct other) + { + return (x == other.x) && (y == other.y) && (z == other.z) && (w == other.w); + } + public override bool Equals(object other) + { + return Equals((SomeLargeStruct)other); + } + + public override int GetHashCode() { return x; } + } + + class SomeClass : IEquatable + { + public SomeClass(int _xVal) + { + x = _xVal; + y = 0; + z = 0; + w = 0; + } + public int x; + public int y; + public int z; + public int w; + + public bool Equals(SomeClass other) + { + return (x == other.x) && (y == other.y) && (z == other.z) && (w == other.w); + } + public override bool Equals(object other) + { + return Equals((SomeClass)other); + } + + public override int GetHashCode() { return x; } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool DoLargeStructMDArrayTest(SomeLargeStruct testValue) + { + SomeLargeStruct[,] array = new SomeLargeStruct[2,2]; + array[0,0] = testValue; + if (!CheckArrayVal(ref array[0,0], testValue)) + { + return false; + } + if (!testValue.Equals(array[0,0])) + { + return false; + } + + return true; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool DoGenericArrayTest (T testValue) where T:IEquatable + { + T[,] array = new T[2,2]; + array[0,0] = testValue; + if (!CheckArrayVal(ref array[0,0], testValue)) + { + return false; + } + if (!testValue.Equals(array[0,0])) + { + return false; + } + + return true; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestGenericMDArrayBehavior() + { + if (!DoGenericArrayTest(42)) + { + return false; + } + + if (!DoGenericArrayTest(new SomeClass(42))) + { + return false; + } + + SomeLargeStruct testStruct = new SomeLargeStruct(42); + if (!DoGenericArrayTest(testStruct)) + { + return false; + } + + if (!DoLargeStructMDArrayTest(testStruct)) + { + return false; + } + + return true; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool ArrayLdtokenTests() + { + // We're testing that mapping from ldtoken to RuntimeMethodHandle works for various ways that + // ldtokens can be referenced (either via a generic token, or not. + // (there are slightly different codepaths in crossgen for this) + // Incorrect encoding will trigger a BadImageFormatException + RuntimeMethodHandle rmhCtor1 = default(RuntimeMethodHandle); + RuntimeMethodHandle rmhCtor2 = default(RuntimeMethodHandle); + RuntimeMethodHandle rmhSet = default(RuntimeMethodHandle); + RuntimeMethodHandle rmhGet = default(RuntimeMethodHandle); + RuntimeMethodHandle rmhAddress = default(RuntimeMethodHandle); + HelperGenericILCode.LdTokenArrayMethods(ref rmhCtor1, ref rmhCtor2, ref rmhSet, ref rmhGet, ref rmhAddress); + HelperGenericILCode.LdTokenArrayMethods(ref rmhCtor1, ref rmhCtor2, ref rmhSet, ref rmhGet, ref rmhAddress); + HelperILCode.LdTokenArrayMethodsInt(ref rmhCtor1, ref rmhCtor2, ref rmhSet, ref rmhGet, ref rmhAddress); + HelperILCode.LdTokenArrayMethodsString(ref rmhCtor1, ref rmhCtor2, ref rmhSet, ref rmhGet, ref rmhAddress); + + return true; + } + public static int Main(string[] args) { _passedTests = new List(); @@ -1691,6 +1830,8 @@ public static int Main(string[] args) RunTest("ExplicitlySizedStructTest", ExplicitlySizedStructTest()); RunTest("ExplicitlySizedClassTest", ExplicitlySizedClassTest()); RunTest("GenericLdtokenTest", GenericLdtokenTest()); + RunTest("ArrayLdtokenTests", ArrayLdtokenTests()); + RunTest("TestGenericMDArrayBehavior", TestGenericMDArrayBehavior()); File.Delete(TextFileName); diff --git a/src/tests/readytorun/crossgen2/helperildll.il b/src/tests/readytorun/crossgen2/helperildll.il index 4a4194454a960a..752d16c83c1517 100644 --- a/src/tests/readytorun/crossgen2/helperildll.il +++ b/src/tests/readytorun/crossgen2/helperildll.il @@ -40,6 +40,55 @@ ret } + .method public hidebysig static void LdTokenArrayMethodsInt(valuetype[mscorlib]System.RuntimeMethodHandle& ctor, valuetype[mscorlib]System.RuntimeMethodHandle& ctor2, valuetype[mscorlib]System.RuntimeMethodHandle& set, valuetype[mscorlib]System.RuntimeMethodHandle& get, valuetype[mscorlib]System.RuntimeMethodHandle& address) + { + ldarg 0 + ldtoken method instance void int32[,]::.ctor(int32, int32, int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 1 + ldtoken method instance void int32[,]::.ctor(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 2 + ldtoken method instance void int32[,]::Set(int32, int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 3 + ldtoken method instance int32 int32[,]::Get(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 4 + ldtoken method instance int32& int32[,]::Address(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + ret + } + + .method public hidebysig static void LdTokenArrayMethodsString(valuetype[mscorlib]System.RuntimeMethodHandle& ctor, valuetype[mscorlib]System.RuntimeMethodHandle& ctor2, valuetype[mscorlib]System.RuntimeMethodHandle& set, valuetype[mscorlib]System.RuntimeMethodHandle& get, valuetype[mscorlib]System.RuntimeMethodHandle& address) + { + ldarg 0 + ldtoken method instance void string[,]::.ctor(int32, int32, int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 1 + ldtoken method instance void string[,]::.ctor(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 2 + ldtoken method instance void string[,]::Set(int32, int32, string) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 3 + ldtoken method instance string string[,]::Get(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 4 + ldtoken method instance string& string[,]::Address(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + ret + } + + .method public hidebysig static valuetype[mscorlib]System.RuntimeMethodHandle ForceStuffToBeCompiled() cil managed noinlining { call valuetype[mscorlib]System.RuntimeMethodHandle class HelperGenericILCode`1::GetGenericFunctionMethodHandle>() @@ -50,6 +99,22 @@ call valuetype[mscorlib]System.RuntimeMethodHandle HelperILCode::GetGenericFunctionMethodHandle() ret } + .method public hidebysig static void ForceStuffToBeCompiled3(valuetype[mscorlib]System.RuntimeMethodHandle& ctor, valuetype[mscorlib]System.RuntimeMethodHandle& ctor2, valuetype[mscorlib]System.RuntimeMethodHandle& set, valuetype[mscorlib]System.RuntimeMethodHandle& get, valuetype[mscorlib]System.RuntimeMethodHandle& address) cil managed noinlining + { + ldarg 0 + ldarg 1 + ldarg 2 + ldarg 3 + ldarg 4 + call void class HelperGenericILCode`1::LdTokenArrayMethods(valuetype[mscorlib]System.RuntimeMethodHandle&, valuetype[mscorlib]System.RuntimeMethodHandle&, valuetype[mscorlib]System.RuntimeMethodHandle&, valuetype[mscorlib]System.RuntimeMethodHandle&, valuetype[mscorlib]System.RuntimeMethodHandle&) + ldarg 0 + ldarg 1 + ldarg 2 + ldarg 3 + ldarg 4 + call void class HelperGenericILCode`1::LdTokenArrayMethods(valuetype[mscorlib]System.RuntimeMethodHandle& ctor, valuetype[mscorlib]System.RuntimeMethodHandle& ctor2, valuetype[mscorlib]System.RuntimeMethodHandle& set, valuetype[mscorlib]System.RuntimeMethodHandle& get, valuetype[mscorlib]System.RuntimeMethodHandle& address) + ret + } } .class auto ansi public beforefieldinit HelperGenericILCode`1 @@ -66,4 +131,27 @@ ldtoken method instance int32 valuetype [helperdll]GenericStructForLdtoken`1::GenericFunction(!0, !!0, string, int32) ret } + .method public hidebysig static void LdTokenArrayMethods(valuetype[mscorlib]System.RuntimeMethodHandle& ctor, valuetype[mscorlib]System.RuntimeMethodHandle& ctor2, valuetype[mscorlib]System.RuntimeMethodHandle& set, valuetype[mscorlib]System.RuntimeMethodHandle& get, valuetype[mscorlib]System.RuntimeMethodHandle& address) + { + ldarg 0 + ldtoken method instance void !0[,]::.ctor(int32, int32, int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 1 + ldtoken method instance void !0[,]::.ctor(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 2 + ldtoken method instance void !0[,]::Set(int32, int32, !0) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 3 + ldtoken method instance !0 !0[,]::Get(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + + ldarg 4 + ldtoken method instance !0& !0[,]::Address(int32, int32) + stobj valuetype[mscorlib]System.RuntimeMethodHandle + ret + } }