This was found in Pri0 testing. The LDTOKEN data structures didn't have enough information for generic method instantiation arguments. The Pri0 test was around generic virtual methods, but this is a more general issue so adding an extra test for that.
I'm also changing how `NodeFactory.ReflectedMethod` works - it will now require being called with canonical things explicitly (and asserts if it isn't) instead of canonicalizing behind the scenes. This was obscuring the problem.
&& systemTypeValue.RepresentedType.Type.GetParameterlessConstructor() is MethodDesc ctorMethod
&& !reflectionMarker.Factory.MetadataManager.IsReflectionBlocked(ctorMethod))
{
- reflectionMarker.Dependencies.Add(reflectionMarker.Factory.ReflectedMethod(ctorMethod), "Marshal API");
+ reflectionMarker.Dependencies.Add(reflectionMarker.Factory.ReflectedMethod(ctorMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Marshal API");
}
}
}
// Make a new list in case we need to abort.
var caDependencies = factory.MetadataManager.GetDependenciesForCustomAttribute(factory, constructor, decodedValue, parent) ?? new DependencyList();
- caDependencies.Add(factory.ReflectedMethod(constructor), "Attribute constructor");
+ caDependencies.Add(factory.ReflectedMethod(constructor.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Attribute constructor");
caDependencies.Add(factory.ReflectedType(constructor.OwningType), "Attribute type");
if (AddDependenciesFromCustomAttributeBlob(caDependencies, factory, constructor.OwningType, decodedValue))
setterMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(setterMethod, (InstantiatedType)attributeType);
}
- dependencies.Add(factory.ReflectedMethod(setterMethod), "Custom attribute blob");
+ dependencies.Add(factory.ReflectedMethod(setterMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Custom attribute blob");
}
return true;
private NodeCache<MethodDesc, ReflectedMethodNode> _reflectedMethods;
public ReflectedMethodNode ReflectedMethod(MethodDesc method)
{
- // We track reflectability at canonical method body level
- method = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
-
return _reflectedMethods.GetOrAdd(method);
}
}
dependencies ??= new DependencyList();
- dependencies.Add(factory.ReflectedMethod(method), reason);
+ dependencies.Add(factory.ReflectedMethod(method.GetCanonMethodTarget(CanonicalFormKind.Specific)), reason);
return true;
}
if (!_factory.MetadataManager.IsReflectionBlocked(method))
{
_factory.TypeSystemContext.EnsureLoadableMethod(method);
- _rootAdder(_factory.ReflectedMethod(method), reason);
+ _rootAdder(_factory.ReflectedMethod(method.GetCanonMethodTarget(CanonicalFormKind.Specific)), reason);
}
}
if (!IsReflectionBlocked(invokeMethod))
{
dependencies ??= new DependencyList();
- dependencies.Add(factory.ReflectedMethod(invokeMethod), "Delegate invoke method is always reflectable");
+ dependencies.Add(factory.ReflectedMethod(invokeMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Delegate invoke method is always reflectable");
}
}
dependencies ??= new CombinedDependencyList();
dependencies.Add(new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(
- factory.ReflectedMethod(reflectedMethod),
+ factory.ReflectedMethod(reflectedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)),
factory.ReflectedMethod(reflectedMethod.GetTypicalMethodDefinition()),
"Methods have same reflectability"));
}
dependencies ??= new DependencyList();
if (!IsReflectionBlocked(method))
- dependencies.Add(factory.ReflectedMethod(method), "LDTOKEN method");
+ {
+ MethodDesc canonicalMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
+ dependencies.Add(factory.ReflectedMethod(canonicalMethod), "LDTOKEN method");
+
+ if (canonicalMethod != method)
+ {
+ foreach (TypeDesc instArg in method.Instantiation)
+ {
+ dependencies.Add(factory.ReflectedType(instArg), "LDTOKEN method");
+ }
+ }
+ }
}
public override void GetDependenciesDueToDelegateCreation(ref DependencyList dependencies, NodeFactory factory, MethodDesc target)
if (!IsReflectionBlocked(target))
{
dependencies ??= new DependencyList();
- dependencies.Add(factory.ReflectedMethod(target), "Target of a delegate");
+ dependencies.Add(factory.ReflectedMethod(target.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Target of a delegate");
if (target.IsVirtual)
dependencies.Add(factory.DelegateTargetVirtualMethod(target.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Target of a delegate");
if (method.IsAbstract && GetMetadataCategory(method) != 0)
{
dependencies ??= new DependencyList();
- dependencies.Add(factory.ReflectedMethod(method), "Abstract reflectable method");
+ dependencies.Add(factory.ReflectedMethod(method.GetCanonMethodTarget(CanonicalFormKind.Specific)), "Abstract reflectable method");
}
}
}
TestIsValueTypeWithoutTypeHandle.Run();
TestMdArrayLoad.Run();
TestByRefTypeLoad.Run();
+ TestGenericLdtoken.Run();
+ TestAbstractGenericLdtoken.Run();
//
// Mostly functionality tests
}
}
+ class TestGenericLdtoken
+ {
+ class Base
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Base GetInstance() => new Base();
+ public virtual Type GrabType<T>() => typeof(T);
+ }
+
+ class Derived : Base
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static new Base GetInstance() => new Derived();
+ public override Type GrabType<T>() => typeof(T);
+ }
+
+ class Generic<T> { }
+
+ class Atom { }
+
+ public static void Run()
+ {
+ Expression<Func<Type>> grabType = () => Base.GetInstance().GrabType<Generic<Atom>>();
+ Console.WriteLine(grabType.Compile()().FullName);
+ }
+ }
+
+ class TestAbstractGenericLdtoken
+ {
+ abstract class Base
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Base GetInstance() => null;
+ public abstract Type GrabType<T>();
+ }
+
+ class Generic<T> { }
+
+ class Atom { }
+
+ public static void Run()
+ {
+ Expression<Func<Type>> grabType = () => Base.GetInstance().GrabType<Generic<Atom>>();
+ try
+ {
+ grabType.Compile()();
+ }
+ catch (NullReferenceException)
+ {
+ }
+ }
+ }
+
class TestEntryPoint
{
public static void Run()