Skip to content

Commit

Permalink
Always create constructed MethodTable for MdArray & co. (#103696)
Browse files Browse the repository at this point in the history
Arrays that don't implement generic interface methods can be loaded at runtime without any sort of type loader template (their template is the same thing that we just whack into the right shape and there's no associated code because everything is from `System.Array`). But this means we should never create unconstructed MethodTable for these because we could end up in a situation where a single type has two `MethodTable`s. The regression test demonstrates how that can happen (the `is` check only forces unconstructed form of the `MethodTable`).

Ran into this while working on a different PR, but I don't want to clutter that one with this.
  • Loading branch information
MichalStrehovsky authored Jun 19, 2024
1 parent b00d30c commit 63b613c
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,19 @@ protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFact
if (_type.IsInterface)
dependencies.Add(factory.InterfaceUse(_type.GetTypeDefinition()), "Interface is used");

// Array types that don't have generic interface methods can be created out of thin air
// at runtime by the type loader. We should never emit non-constructed forms of these MethodTables.
// There's similar logic for generic types, but that one is a conditional dependency conditioned
// on the presence of the type loader template for the canonical form of the type.
if (_type.IsArrayTypeWithoutGenericInterfaces())
{
IEETypeNode maximallyConstructableType = factory.MaximallyConstructableType(_type);
if (maximallyConstructableType != this)
{
dependencies.Add(maximallyConstructableType, "Type is template-loadable");
}
}

if (EmitVirtualSlots)
{
if (!_type.IsArrayTypeWithoutGenericInterfaces())
Expand Down
16 changes: 16 additions & 0 deletions src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ private static int Main()
TestGenericMethodOnGenericType.Run();
TestIsValueTypeWithoutTypeHandle.Run();
TestMdArrayLoad.Run();
TestMdArrayLoad2.Run();
TestByRefTypeLoad.Run();
TestGenericLdtoken.Run();
TestAbstractGenericLdtoken.Run();
Expand Down Expand Up @@ -2443,6 +2444,21 @@ public static void Run()
}
}

class TestMdArrayLoad2
{
class Atom { }

public static object MakeMdArray<T>() => new T[1,1,1];

public static void Run()
{
var mi = typeof(TestMdArrayLoad2).GetMethod(nameof(MakeMdArray)).MakeGenericMethod(GetAtom());
if (mi.Invoke(null, Array.Empty<object>()) is not Atom[,,])
throw new Exception();
static Type GetAtom() => typeof(Atom);
}
}

class TestByRefTypeLoad
{
class Atom { }
Expand Down

0 comments on commit 63b613c

Please sign in to comment.