- MDArrays are special and method references to the methods needs to be encoded with their type in more cases than normal methods
- Only generate the owner type if the memberref does not encode the same owner type
- Add tests for various multidimensional array scenarios to crossgen2smoke
Fix issue #38260
return arrayMethod != null && arrayMethod.Kind == ArrayMethodKind.Address;
}
+
+ /// <summary>
+ /// Returns true if '<paramref name="method"/>' is one of the special methods on multidimensional array types (set, get, address).
+ /// </summary>
+ 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);
+ }
+
/// <summary>
/// Gets a value indicating whether this type has any generic virtual methods.
/// </summary>
using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
// 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)
<ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded/*">
<Issue>https://github.com/dotnet/runtime/issues/38096</Issue>
</ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Generics/Arrays/TypeParameters/MultiDim/**/*">
- <Issue>https://github.com/dotnet/runtime/issues/38260</Issue>
- </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/tailcall_v4/hijacking/*">
<Issue>https://github.com/dotnet/runtime/issues/7597</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Loader/binding/tracing/BinderTracingTest.Basic/*">
<Issue>https://github.com/dotnet/runtime/issues/38290</Issue>
</ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/regressions/Dev12_518401/dev12_518401/dev12_518401/*">
- <Issue>https://github.com/dotnet/runtime/issues/38260</Issue>
- </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/tracing/tracevalidation/tracelogging/tracelogging/*">
<Issue>https://github.com/dotnet/runtime/issues/32728</Issue>
</ExcludeList>
return true;
}
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static bool CheckArrayVal<T>(ref T refVal, T testValue) where T:IEquatable<T>
+ {
+ return refVal.Equals(testValue);
+ }
+
+ struct SomeLargeStruct : IEquatable<SomeLargeStruct>
+ {
+ 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<SomeClass>
+ {
+ 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> (T testValue) where T:IEquatable<T>
+ {
+ 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<int>(42))
+ {
+ return false;
+ }
+
+ if (!DoGenericArrayTest<SomeClass>(new SomeClass(42)))
+ {
+ return false;
+ }
+
+ SomeLargeStruct testStruct = new SomeLargeStruct(42);
+ if (!DoGenericArrayTest<SomeLargeStruct>(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<string>.LdTokenArrayMethods(ref rmhCtor1, ref rmhCtor2, ref rmhSet, ref rmhGet, ref rmhAddress);
+ HelperGenericILCode<object>.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<string>();
RunTest("ExplicitlySizedStructTest", ExplicitlySizedStructTest());
RunTest("ExplicitlySizedClassTest", ExplicitlySizedClassTest());
RunTest("GenericLdtokenTest", GenericLdtokenTest());
+ RunTest("ArrayLdtokenTests", ArrayLdtokenTests());
+ RunTest("TestGenericMDArrayBehavior", TestGenericMDArrayBehavior());
File.Delete(TextFileName);
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<object>::GetGenericFunctionMethodHandle<valuetype [helperdll]GenericStructForLdtoken`1<string>>()
call valuetype[mscorlib]System.RuntimeMethodHandle HelperILCode::GetGenericFunctionMethodHandle<string>()
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<object>::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<int32>::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<T>
ldtoken method instance int32 valuetype [helperdll]GenericStructForLdtoken`1<!0>::GenericFunction<!!0>(!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
+ }
}