Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate type generic composition information as constructed #105133

Merged
merged 4 commits into from
Jul 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using EcmaModule = Internal.TypeSystem.Ecma.EcmaModule;
using CustomAttributeHandle = System.Reflection.Metadata.CustomAttributeHandle;
using ExportedTypeHandle = System.Reflection.Metadata.ExportedTypeHandle;
using FlowAnnotations = ILLink.Shared.TrimAnalysis.FlowAnnotations;

namespace ILCompiler
{
Expand All @@ -32,7 +33,7 @@ public sealed class AnalysisBasedMetadataManager : MetadataManager, ICompilation
public AnalysisBasedMetadataManager(CompilerTypeSystemContext typeSystemContext)
: this(typeSystemContext, new FullyBlockedMetadataBlockingPolicy(),
new FullyBlockedManifestResourceBlockingPolicy(), null, new NoStackTraceEmissionPolicy(),
new NoDynamicInvokeThunkGenerationPolicy(), Array.Empty<ModuleDesc>(), Array.Empty<TypeDesc>(),
new NoDynamicInvokeThunkGenerationPolicy(), null, Array.Empty<ModuleDesc>(), Array.Empty<TypeDesc>(),
Array.Empty<ReflectableEntity<TypeDesc>>(), Array.Empty<ReflectableEntity<MethodDesc>>(),
Array.Empty<ReflectableEntity<FieldDesc>>(), Array.Empty<ReflectableCustomAttribute>(),
default)
Expand All @@ -46,14 +47,15 @@ public AnalysisBasedMetadataManager(
string logFile,
StackTraceEmissionPolicy stackTracePolicy,
DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy,
FlowAnnotations flowAnnotations,
IEnumerable<ModuleDesc> modulesWithMetadata,
IEnumerable<TypeDesc> forcedTypes,
IEnumerable<ReflectableEntity<TypeDesc>> reflectableTypes,
IEnumerable<ReflectableEntity<MethodDesc>> reflectableMethods,
IEnumerable<ReflectableEntity<FieldDesc>> reflectableFields,
IEnumerable<ReflectableCustomAttribute> reflectableAttributes,
MetadataManagerOptions options)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy, options)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy, options, flowAnnotations)
{
_modulesWithMetadata = new List<ModuleDesc>(modulesWithMetadata);
_forcedTypes = new List<TypeDesc>(forcedTypes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1252,9 +1252,21 @@ protected void OutputGenericInstantiationDetails(NodeFactory factory, ref Object
else
objData.EmitPointerReloc(typeDefNode);

ISymbolNode compositionNode = _type.Instantiation.Length > 1
? factory.GenericComposition(_type.Instantiation)
: factory.NecessaryTypeSymbol(_type.Instantiation[0]);
ISymbolNode compositionNode;

if (this == factory.MaximallyConstructableType(_type)
&& factory.MetadataManager.IsTypeInstantiationReflectionVisible(_type))
{
compositionNode = _type.Instantiation.Length > 1
? factory.ConstructedGenericComposition(_type.Instantiation)
: factory.MaximallyConstructableType(_type.Instantiation[0]);
}
else
{
compositionNode = _type.Instantiation.Length > 1
? factory.GenericComposition(_type.Instantiation)
: factory.NecessaryTypeSymbol(_type.Instantiation[0]);
}

if (factory.Target.SupportsRelativePointers)
objData.EmitReloc(compositionNode, RelocType.IMAGE_REL_BASED_RELPTR32);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ namespace ILCompiler.DependencyAnalysis
/// </summary>
public class GenericCompositionNode : ObjectNode, ISymbolDefinitionNode
{
private Instantiation _details;
private readonly Instantiation _details;
private readonly bool _constructed;

internal GenericCompositionNode(Instantiation details)
internal GenericCompositionNode(Instantiation details, bool constructed)
{
_details = details;
_constructed = constructed;
}

public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !_constructed && factory.ConstructedGenericComposition(_details).Marked;

public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("__GenericInstance"u8);
Expand Down Expand Up @@ -62,10 +66,12 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)

foreach (var typeArg in _details)
{
IEETypeNode node = _constructed ? factory.MaximallyConstructableType(typeArg) : factory.NecessaryTypeSymbol(typeArg);

if (useRelativePointers)
builder.EmitReloc(factory.NecessaryTypeSymbol(typeArg), RelocType.IMAGE_REL_BASED_RELPTR32);
builder.EmitReloc(node, RelocType.IMAGE_REL_BASED_RELPTR32);
else
builder.EmitPointerReloc(factory.NecessaryTypeSymbol(typeArg));
builder.EmitPointerReloc(node);
}

return builder.ToObjectData();
Expand All @@ -81,6 +87,10 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer
if (compare != 0)
return compare;

compare = _constructed.CompareTo(otherComposition._constructed);
if (compare != 0)
return compare;

for (int i = 0; i < _details.Length; i++)
{
compare = comparer.Compare(_details[i], otherComposition._details[i]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,12 @@ private void CreateNodeCaches()

_genericCompositions = new NodeCache<Instantiation, GenericCompositionNode>((Instantiation details) =>
{
return new GenericCompositionNode(details);
return new GenericCompositionNode(details, constructed: false);
});

_constructedGenericCompositions = new NodeCache<Instantiation, GenericCompositionNode>((Instantiation details) =>
{
return new GenericCompositionNode(details, constructed: true);
});

_genericVariances = new NodeCache<GenericVarianceDetails, GenericVarianceNode>((GenericVarianceDetails details) =>
Expand Down Expand Up @@ -847,6 +852,13 @@ internal ISymbolNode GenericComposition(Instantiation details)
return _genericCompositions.GetOrAdd(details);
}

private NodeCache<Instantiation, GenericCompositionNode> _constructedGenericCompositions;

internal ISymbolNode ConstructedGenericComposition(Instantiation details)
{
return _constructedGenericCompositions.GetOrAdd(details);
}

private NodeCache<GenericVarianceDetails, GenericVarianceNode> _genericVariances;

internal ISymbolNode GenericVariance(GenericVarianceDetails details)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using MethodIL = Internal.IL.MethodIL;
using CustomAttributeValue = System.Reflection.Metadata.CustomAttributeValue<Internal.TypeSystem.TypeDesc>;
using MethodSignature = Internal.TypeSystem.MethodSignature;
using FlowAnnotations = ILLink.Shared.TrimAnalysis.FlowAnnotations;

using MetadataRecord = Internal.Metadata.NativeFormat.Writer.MetadataRecord;
using MetadataWriter = Internal.Metadata.NativeFormat.Writer.MetadataWriter;
Expand Down Expand Up @@ -82,12 +83,14 @@ private readonly SortedSet<TypeGVMEntriesNode> _typeGVMEntries

private List<(DehydratableObjectNode Node, ObjectNode.ObjectData Data)> _dehydratableData = new List<(DehydratableObjectNode Node, ObjectNode.ObjectData data)>();

internal FlowAnnotations FlowAnnotations { get; }

internal NativeLayoutInfoNode NativeLayoutInfo { get; private set; }

public MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy,
ManifestResourceBlockingPolicy resourceBlockingPolicy, string logFile, StackTraceEmissionPolicy stackTracePolicy,
DynamicInvokeThunkGenerationPolicy dynamicInvokeThunkGenerationPolicy,
MetadataManagerOptions options)
MetadataManagerOptions options, FlowAnnotations flowAnnotations)
{
_typeSystemContext = typeSystemContext;
_blockingPolicy = blockingPolicy;
Expand All @@ -96,6 +99,8 @@ public MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBloc
_options = options;
_metadataLogFile = logFile;
_stackTraceEmissionPolicy = stackTracePolicy;

FlowAnnotations = flowAnnotations;
}

public bool IsDataDehydrated => (_options & MetadataManagerOptions.DehydrateData) != 0;
Expand Down Expand Up @@ -344,6 +349,23 @@ protected virtual void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)

protected virtual bool AllMethodsCanBeReflectable => false;

public bool IsTypeInstantiationReflectionVisible(TypeDesc type)
{
if (FlowAnnotations == null)
return false;

if (FlowAnnotations.HasGenericParameterAnnotation(type))
return true;

foreach (TypeDesc instArg in type.Instantiation)
{
if (IsTypeInstantiationReflectionVisible(instArg))
return true;
}

return false;
}

/// <summary>
/// Is a method that is reflectable a method which should be placed into the invoke map as invokable?
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ private static (string AttributeName, DiagnosticId Id)[] _requiresAttributeMisma
private readonly HashSet<string> _trimmedAssemblies;
private readonly List<string> _satelliteAssemblyFiles;

internal FlowAnnotations FlowAnnotations { get; }

internal Logger Logger { get; }

public UsageBasedMetadataManager(
Expand All @@ -86,12 +84,11 @@ public UsageBasedMetadataManager(
IEnumerable<string> additionalRootedAssemblies,
IEnumerable<string> trimmedAssemblies,
IEnumerable<string> satelliteAssemblyFilePaths)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy, options)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy, options, flowAnnotations)
{
_compilationModuleGroup = group;
_generationOptions = generationOptions;

FlowAnnotations = flowAnnotations;
Logger = logger;

_linkAttributesHashTable = new LinkAttributesHashTable(Logger, featureSwitchValues);
Expand Down Expand Up @@ -896,7 +893,7 @@ public MetadataManager ToAnalysisBasedMetadataManager()
}

return new AnalysisBasedMetadataManager(
_typeSystemContext, _blockingPolicy, _resourceBlockingPolicy, _metadataLogFile, _stackTraceEmissionPolicy, _dynamicInvokeThunkGenerationPolicy,
_typeSystemContext, _blockingPolicy, _resourceBlockingPolicy, _metadataLogFile, _stackTraceEmissionPolicy, _dynamicInvokeThunkGenerationPolicy, FlowAnnotations,
_modulesWithMetadata, _typesWithForcedEEType, reflectableTypes.ToEnumerable(), reflectableMethods.ToEnumerable(),
reflectableFields.ToEnumerable(), _customAttributesWithMetadata, _options);
}
Expand Down
43 changes: 42 additions & 1 deletion src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ private static int Main()
TestAbstractGenericLdtoken.Run();
TestTypeHandlesVisibleFromIDynamicInterfaceCastable.Run();
TestCompilerGeneratedCode.Run();
Test105034Regression.Run();


//
// Mostly functionality tests
Expand Down Expand Up @@ -713,6 +715,45 @@ public static void Run()
}
}

class Test105034Regression
{
interface IFactory
{
object Make();
}

interface IOption<T> where T : new() { }

class OptionFactory<T> : IFactory where T : class, new()
{
public object Make() => new T();
}

class Gen<T> { }

struct Atom { }

static Type Register<T>() => typeof(T).GetGenericArguments()[0];
static IFactory Activate(Type t) => (IFactory)Activator.CreateInstance(typeof(OptionFactory<>).MakeGenericType(t));

public static void Run()
{
Console.WriteLine(nameof(Test105034Regression));

Wrap<Atom>();

static void Wrap<T>()
{

Type t = Register();
static Type Register() => Register<IOption<Gen<T>>>();

var f = Activate(t);
f.Make();
}
}
}

class TestCreateDelegate
{
internal class Greeter
Expand Down Expand Up @@ -2485,7 +2526,7 @@ class TestMdArrayLoad2
{
class Atom { }

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

public static void Run()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,15 +269,7 @@ public static void Run()
throw new Exception();
}

// ...but not nullable...
{
Array arr = new Nullable<NeverAllocated2>[1];
arr.GetValue(0);
ThrowIfPresent(typeof(TestArrayElementTypeOperations), nameof(Marker2));
}


// ...or reference type element types
// ...but not reference type element types
{
Array arr = new NeverAllocated3[1];
arr.GetValue(0);
Expand Down
Loading