Build header tables using metadata manager (#6222)
* Build header tables using metadata manager * Enable MetadataManager to track use of types / methods * Introduce `AvailableType` which replaces the CoreRT EETypeNode. Ready-to-run doesn't emit types directly into the image but records their use and fills a table of available types used for type resolution between ready-to-run modules by the runtime. * Add dependency tracking in a few existing places where references to types are being made. In library compilation mode, the non-private types will be rooted so they always end up in the available types table. * Use a single NodeCache for method entrypoints instead of a separate dictionary for ready-to-run entrypoints. To smooth over the API differences between the base `NodeFactory` and `ReadyToRunCodegenNodeFactory`, allow a custom GetOrAdd method that takes a creator callback. * Switch over `RuntimeFunctionsTable`, `TypesTable`, `MethodEntryPointTable` to use metadata manager for the list of types / methods to emit entries for.
This commit is contained in:
Родитель
ee5bc9f6ff
Коммит
3d56b11db6
|
@ -149,60 +149,18 @@ namespace ILCompiler.DependencyAnalysis
|
|||
{
|
||||
return _cache.GetOrAdd(key, _creator);
|
||||
}
|
||||
|
||||
public TValue GetOrAdd(TKey key, Func<TKey, TValue> creator)
|
||||
{
|
||||
return _cache.GetOrAdd(key, creator);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateNodeCaches()
|
||||
{
|
||||
_typeSymbols = new NodeCache<TypeDesc, IEETypeNode>((TypeDesc type) =>
|
||||
{
|
||||
Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
|
||||
if (_compilationModuleGroup.ContainsType(type))
|
||||
{
|
||||
if (type.IsGenericDefinition)
|
||||
{
|
||||
return new GenericDefinitionEETypeNode(this, type);
|
||||
}
|
||||
else if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
|
||||
{
|
||||
return new CanonicalDefinitionEETypeNode(this, type);
|
||||
}
|
||||
else if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
|
||||
{
|
||||
return new NecessaryCanonicalEETypeNode(this, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new EETypeNode(this, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ExternEETypeSymbolNode(this, type);
|
||||
}
|
||||
});
|
||||
_typeSymbols = new NodeCache<TypeDesc, IEETypeNode>(CreateNecessaryTypeNode);
|
||||
|
||||
_constructedTypeSymbols = new NodeCache<TypeDesc, IEETypeNode>((TypeDesc type) =>
|
||||
{
|
||||
// Canonical definition types are *not* constructed types (call NecessaryTypeSymbol to get them)
|
||||
Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
|
||||
Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
|
||||
|
||||
if (_compilationModuleGroup.ContainsType(type))
|
||||
{
|
||||
if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
|
||||
{
|
||||
return new CanonicalEETypeNode(this, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ConstructedEETypeNode(this, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ExternEETypeSymbolNode(this, type);
|
||||
}
|
||||
});
|
||||
_constructedTypeSymbols = new NodeCache<TypeDesc, IEETypeNode>(CreateConstructedTypeNode);
|
||||
|
||||
_clonedTypeSymbols = new NodeCache<TypeDesc, IEETypeNode>((TypeDesc type) =>
|
||||
{
|
||||
|
@ -483,6 +441,57 @@ namespace ILCompiler.DependencyAnalysis
|
|||
WindowsDebugData = new WindowsDebugDataHelper(this);
|
||||
}
|
||||
|
||||
protected virtual IEETypeNode CreateNecessaryTypeNode(TypeDesc type)
|
||||
{
|
||||
Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
|
||||
if (_compilationModuleGroup.ContainsType(type))
|
||||
{
|
||||
if (type.IsGenericDefinition)
|
||||
{
|
||||
return new GenericDefinitionEETypeNode(this, type);
|
||||
}
|
||||
else if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
|
||||
{
|
||||
return new CanonicalDefinitionEETypeNode(this, type);
|
||||
}
|
||||
else if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
|
||||
{
|
||||
return new NecessaryCanonicalEETypeNode(this, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new EETypeNode(this, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ExternEETypeSymbolNode(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IEETypeNode CreateConstructedTypeNode(TypeDesc type)
|
||||
{
|
||||
// Canonical definition types are *not* constructed types (call NecessaryTypeSymbol to get them)
|
||||
Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
|
||||
Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
|
||||
|
||||
if (_compilationModuleGroup.ContainsType(type))
|
||||
{
|
||||
if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
|
||||
{
|
||||
return new CanonicalEETypeNode(this, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ConstructedEETypeNode(this, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ExternEETypeSymbolNode(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract IMethodNode CreateMethodEntrypointNode(MethodDesc method);
|
||||
|
||||
protected abstract IMethodNode CreateUnboxingStubNode(MethodDesc method);
|
||||
|
@ -721,7 +730,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
return _stringAllocators.GetOrAdd(stringConstructor);
|
||||
}
|
||||
|
||||
private NodeCache<MethodDesc, IMethodNode> _methodEntrypoints;
|
||||
protected NodeCache<MethodDesc, IMethodNode> _methodEntrypoints;
|
||||
private NodeCache<MethodDesc, IMethodNode> _unboxingStubs;
|
||||
private NodeCache<IMethodNode, MethodAssociatedDataNode> _methodAssociatedData;
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ namespace ILCompiler
|
|||
protected readonly ManifestResourceBlockingPolicy _resourceBlockingPolicy;
|
||||
|
||||
private List<NonGCStaticsNode> _cctorContextsGenerated = new List<NonGCStaticsNode>();
|
||||
private HashSet<TypeDesc> _typesWithEETypesGenerated = new HashSet<TypeDesc>();
|
||||
private HashSet<TypeDesc> _typesWithConstructedEETypesGenerated = new HashSet<TypeDesc>();
|
||||
private readonly HashSet<TypeDesc> _typesWithEETypesGenerated = new HashSet<TypeDesc>();
|
||||
private readonly HashSet<TypeDesc> _typesWithConstructedEETypesGenerated = new HashSet<TypeDesc>();
|
||||
private HashSet<MethodDesc> _methodsGenerated = new HashSet<MethodDesc>();
|
||||
private HashSet<GenericDictionaryNode> _genericDictionariesGenerated = new HashSet<GenericDictionaryNode>();
|
||||
private HashSet<IMethodBodyNode> _methodBodiesGenerated = new HashSet<IMethodBodyNode>();
|
||||
|
@ -560,7 +560,7 @@ namespace ILCompiler
|
|||
return _genericDictionariesGenerated;
|
||||
}
|
||||
|
||||
internal IEnumerable<MethodDesc> GetCompiledMethods()
|
||||
public IEnumerable<MethodDesc> GetCompiledMethods()
|
||||
{
|
||||
return _methodsGenerated;
|
||||
}
|
||||
|
|
|
@ -72,14 +72,6 @@ namespace ILCompiler.DependencyAnalysis
|
|||
_rdataSectionIndex = sectionBuilder.AddSection(".rdata", SectionCharacteristics.ContainsInitializedData | SectionCharacteristics.MemRead, 512);
|
||||
_dataSectionIndex = sectionBuilder.AddSection(".data", SectionCharacteristics.ContainsInitializedData | SectionCharacteristics.MemWrite | SectionCharacteristics.MemRead, 512);
|
||||
|
||||
foreach (var depNode in _nodes)
|
||||
{
|
||||
if (depNode is EETypeNode eeTypeNode)
|
||||
{
|
||||
_nodeFactory.TypesTable.Add(eeTypeNode);
|
||||
}
|
||||
}
|
||||
|
||||
int nodeIndex = -1;
|
||||
foreach (var depNode in _nodes)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
||||
{
|
||||
class ExternalTypeNode : DependencyNodeCore<NodeFactory>, IEETypeNode
|
||||
{
|
||||
private readonly TypeDesc _type;
|
||||
|
||||
public ExternalTypeNode(NodeFactory factory, TypeDesc type)
|
||||
{
|
||||
_type = type;
|
||||
|
||||
//
|
||||
// This check encodes rules specific to CoreRT. Ie, no function pointer classes allowed.
|
||||
// Eventually we will hit situations where this check fails when it shouldn't and we'll need to
|
||||
// split the logic. It's a good sanity check for the time being though.
|
||||
//
|
||||
EETypeNode.CheckCanGenerateEEType(factory, type);
|
||||
}
|
||||
|
||||
public TypeDesc Type => _type;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public bool RepresentsIndirectionCell => false;
|
||||
|
||||
public int ClassCode => -1044459;
|
||||
|
||||
public override bool InterestingForDynamicDependencyAnalysis => false;
|
||||
|
||||
public override bool HasDynamicDependencies => false;
|
||||
|
||||
public override bool HasConditionalStaticDependencies => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(nameMangler.GetMangledTypeName(_type));
|
||||
}
|
||||
|
||||
public int CompareToImpl(ISortableNode other, CompilerComparer comparer)
|
||||
{
|
||||
return comparer.Compare(Type, ((AvailableType)other).Type);
|
||||
}
|
||||
|
||||
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) => null;
|
||||
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => null;
|
||||
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) => null;
|
||||
|
||||
protected override string GetName(NodeFactory factory) => $"Externally referenced type {Type.ToString()}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
||||
{
|
||||
public class AvailableType : DependencyNodeCore<NodeFactory>, IEETypeNode
|
||||
{
|
||||
private readonly TypeDesc _type;
|
||||
|
||||
public AvailableType(NodeFactory factory, TypeDesc type)
|
||||
{
|
||||
_type = type;
|
||||
|
||||
//
|
||||
// This check encodes rules specific to CoreRT. Ie, no function pointer classes allowed.
|
||||
// Eventually we will hit situations where this check fails when it shouldn't and we'll need to
|
||||
// split the logic. It's a good sanity check for the time being though.
|
||||
//
|
||||
EETypeNode.CheckCanGenerateEEType(factory, type);
|
||||
}
|
||||
|
||||
public TypeDesc Type => _type;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public bool RepresentsIndirectionCell => false;
|
||||
|
||||
public int ClassCode => 345483495;
|
||||
|
||||
public override bool InterestingForDynamicDependencyAnalysis => false;
|
||||
|
||||
public override bool HasDynamicDependencies => false;
|
||||
|
||||
public override bool HasConditionalStaticDependencies => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(nameMangler.GetMangledTypeName(_type));
|
||||
}
|
||||
|
||||
public int CompareToImpl(ISortableNode other, CompilerComparer comparer)
|
||||
{
|
||||
return comparer.Compare(Type, ((AvailableType)other).Type);
|
||||
}
|
||||
|
||||
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) => null;
|
||||
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => null;
|
||||
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) => null;
|
||||
|
||||
protected override string GetName(NodeFactory factory) => $"Available type {Type.ToString()}";
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
}
|
||||
|
||||
public MethodDesc Method => _methodDesc;
|
||||
public MethodWithGCInfo MethodCodeNode => _localMethod;
|
||||
|
||||
public override int ClassCode => 458823351;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
}
|
||||
}
|
||||
|
||||
List<EntryPoint> _ridToEntryPoint;
|
||||
private List<EntryPoint> _ridToEntryPoint;
|
||||
|
||||
public MethodEntryPointTableNode(TargetDetails target)
|
||||
: base(target)
|
||||
|
@ -200,6 +200,19 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, Array.Empty<ISymbolDefinitionNode>());
|
||||
}
|
||||
|
||||
foreach (MethodDesc method in factory.MetadataManager.GetCompiledMethods())
|
||||
{
|
||||
MethodWithGCInfo methodCodeNode = factory.MethodEntrypoint(method) as MethodWithGCInfo;
|
||||
if (methodCodeNode == null)
|
||||
{
|
||||
methodCodeNode = ((ExternalMethodImport)factory.MethodEntrypoint(method))?.MethodCodeNode;
|
||||
if (methodCodeNode == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
Add(methodCodeNode, ((ReadyToRunCodegenNodeFactory)factory).RuntimeFunctionsTable.GetIndex(methodCodeNode));
|
||||
}
|
||||
|
||||
NativeWriter writer = new NativeWriter();
|
||||
|
||||
Section arraySection = writer.NewSection();
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
|
@ -43,10 +44,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
protected override void OnMarked(NodeFactory factory)
|
||||
{
|
||||
ReadyToRunCodegenNodeFactory r2rFactory = (ReadyToRunCodegenNodeFactory)factory;
|
||||
// Marked method - add runtime & entry point table entry
|
||||
r2rFactory.RuntimeFunctionsGCInfo.AddEmbeddedObject(GCInfoNode);
|
||||
int index = r2rFactory.RuntimeFunctionsTable.Add(this);
|
||||
r2rFactory.MethodEntryPointTable.Add(this, index);
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
|
||||
|
|
|
@ -44,5 +44,12 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
{
|
||||
return _typeToken.CompareTo(((NewArrayFixupSignature)other)._typeToken);
|
||||
}
|
||||
|
||||
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
|
||||
{
|
||||
DependencyList dependencies = new DependencyList();
|
||||
dependencies.Add(factory.NecessaryTypeSymbol(_arrayType.ElementType), "Type used as array element");
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
|
@ -44,5 +45,12 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
{
|
||||
return _typeToken.CompareTo(((NewObjectFixupSignature)other)._typeToken);
|
||||
}
|
||||
|
||||
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
|
||||
{
|
||||
DependencyList dependencies = new DependencyList();
|
||||
dependencies.Add(factory.ConstructedTypeSymbol(_typeDesc), "Type constructed through new object fixup");
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,26 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
||||
{
|
||||
public class RuntimeFunctionsTableNode : HeaderTableNode
|
||||
{
|
||||
private readonly List<MethodWithGCInfo> _methodNodes;
|
||||
private List<MethodWithGCInfo> _methodNodes;
|
||||
private Dictionary<MethodWithGCInfo, int> _insertedMethodNodes;
|
||||
private readonly NodeFactory _nodeFactory;
|
||||
|
||||
public RuntimeFunctionsTableNode(TargetDetails target)
|
||||
: base(target)
|
||||
public RuntimeFunctionsTableNode(NodeFactory nodeFactory)
|
||||
: base(nodeFactory.Target)
|
||||
{
|
||||
_methodNodes = new List<MethodWithGCInfo>();
|
||||
_nodeFactory = nodeFactory;
|
||||
}
|
||||
|
||||
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
|
@ -24,14 +30,47 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
sb.Append("__ReadyToRunRuntimeFunctionsTable");
|
||||
}
|
||||
|
||||
public int Add(MethodWithGCInfo method)
|
||||
public int GetIndex(MethodWithGCInfo method)
|
||||
{
|
||||
_methodNodes.Add(method);
|
||||
return _methodNodes.Count - 1;
|
||||
#if DEBUG
|
||||
Debug.Assert(_nodeFactory.MarkingComplete);
|
||||
Debug.Assert(method.Marked);
|
||||
#endif
|
||||
if (_methodNodes == null)
|
||||
LayoutRuntimeFunctions();
|
||||
|
||||
return _insertedMethodNodes[method];
|
||||
}
|
||||
|
||||
private void LayoutRuntimeFunctions()
|
||||
{
|
||||
_methodNodes = new List<MethodWithGCInfo>();
|
||||
_insertedMethodNodes = new Dictionary<MethodWithGCInfo, int>();
|
||||
|
||||
foreach (MethodDesc method in _nodeFactory.MetadataManager.GetCompiledMethods())
|
||||
{
|
||||
MethodWithGCInfo methodCodeNode = _nodeFactory.MethodEntrypoint(method) as MethodWithGCInfo;
|
||||
if (methodCodeNode == null)
|
||||
{
|
||||
methodCodeNode = ((ExternalMethodImport)_nodeFactory.MethodEntrypoint(method))?.MethodCodeNode;
|
||||
if (methodCodeNode == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
_methodNodes.Add(methodCodeNode);
|
||||
_insertedMethodNodes[methodCodeNode] = _methodNodes.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
if (_methodNodes == null)
|
||||
LayoutRuntimeFunctions();
|
||||
|
||||
ObjectDataBuilder runtimeFunctionsBuilder = new ObjectDataBuilder(factory, relocsOnly);
|
||||
|
||||
// Add the symbol representing this object node
|
||||
|
|
|
@ -50,5 +50,12 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
{
|
||||
return _typeToken.CompareTo(((TypeFixupSignature)other)._typeToken);
|
||||
}
|
||||
|
||||
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
|
||||
{
|
||||
DependencyList dependencies = new DependencyList();
|
||||
dependencies.Add(factory.NecessaryTypeSymbol(_typeDesc), "Type referenced in a fixup signature");
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
{
|
||||
public class TypesTableNode : HeaderTableNode
|
||||
{
|
||||
List<(int Rid, EETypeNode Node)> _eeTypeNodes;
|
||||
|
||||
public TypesTableNode(TargetDetails target)
|
||||
: base(target)
|
||||
{
|
||||
_eeTypeNodes = new List<(int Rid, EETypeNode Node)>();
|
||||
}
|
||||
: base(target) {}
|
||||
|
||||
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
|
@ -31,34 +26,33 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
sb.Append("__ReadyToRunAvailableTypesTable");
|
||||
}
|
||||
|
||||
public int Add(EETypeNode eeTypeNode)
|
||||
{
|
||||
if (eeTypeNode.Type is EcmaType ecmaType)
|
||||
{
|
||||
int rid = MetadataTokens.GetToken(ecmaType.Handle) & 0x00FFFFFF;
|
||||
Debug.Assert(rid != 0);
|
||||
int eeTypeIndex = _eeTypeNodes.Count;
|
||||
_eeTypeNodes.Add((Rid: rid, Node: eeTypeNode));
|
||||
return eeTypeIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
NativeWriter writer = new NativeWriter();
|
||||
Section section = writer.NewSection();
|
||||
|
||||
VertexHashtable typesHashtable = new VertexHashtable();
|
||||
section.Place(typesHashtable);
|
||||
|
||||
foreach ((int Rid, EETypeNode Node) eeTypeNode in _eeTypeNodes)
|
||||
|
||||
foreach (TypeDesc type in ((ReadyToRunTableManager)factory.MetadataManager).GetTypesWithAvailableTypes())
|
||||
{
|
||||
int hashCode = eeTypeNode.Node.Type.GetHashCode();
|
||||
typesHashtable.Append(unchecked((uint)hashCode), section.Place(new UnsignedConstant((uint)eeTypeNode.Rid << 1)));
|
||||
int rid = 0;
|
||||
if (type is EcmaType ecmaType)
|
||||
{
|
||||
rid = MetadataTokens.GetToken(ecmaType.Handle) & 0x00FFFFFF;
|
||||
Debug.Assert(rid != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int hashCode = type.GetHashCode();
|
||||
typesHashtable.Append(unchecked((uint)hashCode), section.Place(new UnsignedConstant((uint)rid << 1)));
|
||||
}
|
||||
|
||||
MemoryStream writerContent = new MemoryStream();
|
||||
|
|
|
@ -26,12 +26,12 @@ namespace ILCompiler.DependencyAnalysis
|
|||
private Dictionary<ModuleToken, ISymbolNode> _importStrings;
|
||||
|
||||
public ReadyToRunCodegenNodeFactory(
|
||||
CompilerTypeSystemContext context,
|
||||
CompilerTypeSystemContext context,
|
||||
CompilationModuleGroup compilationModuleGroup,
|
||||
MetadataManager metadataManager,
|
||||
InteropStubManager interopStubManager,
|
||||
NameMangler nameMangler,
|
||||
VTableSliceProvider vtableSliceProvider,
|
||||
InteropStubManager interopStubManager,
|
||||
NameMangler nameMangler,
|
||||
VTableSliceProvider vtableSliceProvider,
|
||||
DictionaryLayoutProvider dictionaryLayoutProvider)
|
||||
: base(context,
|
||||
compilationModuleGroup,
|
||||
|
@ -74,17 +74,12 @@ namespace ILCompiler.DependencyAnalysis
|
|||
|
||||
public ImportSectionNode PrecodeImports;
|
||||
|
||||
Dictionary<MethodDesc, IMethodNode> _methodMap = new Dictionary<MethodDesc, IMethodNode>();
|
||||
|
||||
public IMethodNode MethodEntrypoint(MethodDesc method, ModuleToken token, bool isUnboxingStub = false)
|
||||
{
|
||||
IMethodNode methodNode;
|
||||
if (!_methodMap.TryGetValue(method, out methodNode))
|
||||
return _methodEntrypoints.GetOrAdd(method, (m) =>
|
||||
{
|
||||
methodNode = CreateMethodEntrypointNode(method, token, isUnboxingStub);
|
||||
_methodMap.Add(method, methodNode);
|
||||
}
|
||||
return methodNode;
|
||||
return CreateMethodEntrypointNode(method, token, isUnboxingStub);
|
||||
});
|
||||
}
|
||||
|
||||
private IMethodNode CreateMethodEntrypointNode(MethodDesc method, ModuleToken token, bool isUnboxingStub = false)
|
||||
|
@ -589,7 +584,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
var compilerIdentifierNode = new CompilerIdentifierNode(Target);
|
||||
Header.Add(Internal.Runtime.ReadyToRunSectionType.CompilerIdentifier, compilerIdentifierNode, compilerIdentifierNode);
|
||||
|
||||
RuntimeFunctionsTable = new RuntimeFunctionsTableNode(Target);
|
||||
RuntimeFunctionsTable = new RuntimeFunctionsTableNode(this);
|
||||
Header.Add(Internal.Runtime.ReadyToRunSectionType.RuntimeFunctions, RuntimeFunctionsTable, RuntimeFunctionsTable);
|
||||
|
||||
RuntimeFunctionsGCInfo = new RuntimeFunctionsGCInfoNode();
|
||||
|
@ -608,8 +603,8 @@ namespace ILCompiler.DependencyAnalysis
|
|||
Header.Add(Internal.Runtime.ReadyToRunSectionType.ImportSections, ImportSectionsTable, ImportSectionsTable.StartSymbol);
|
||||
|
||||
EagerImports = new ImportSectionNode(
|
||||
"EagerImports",
|
||||
CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
|
||||
"EagerImports",
|
||||
CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
|
||||
CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_EAGER,
|
||||
(byte)Target.PointerSize,
|
||||
emitPrecode: false);
|
||||
|
@ -660,6 +655,8 @@ namespace ILCompiler.DependencyAnalysis
|
|||
graph.AddRoot(PrecodeImports, "Precode imports are always generated");
|
||||
graph.AddRoot(StringImports, "String imports are always generated");
|
||||
graph.AddRoot(Header, "ReadyToRunHeader is always generated");
|
||||
|
||||
MetadataManager.AttachToDependencyGraph(graph);
|
||||
}
|
||||
|
||||
public IMethodNode ImportedMethodNode(MethodDesc method, bool unboxingStub, ModuleToken token, MethodWithGCInfo localMethod)
|
||||
|
@ -702,9 +699,9 @@ namespace ILCompiler.DependencyAnalysis
|
|||
{
|
||||
methodImport = new ExternalMethodImport(
|
||||
this,
|
||||
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
|
||||
method,
|
||||
token,
|
||||
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
|
||||
method,
|
||||
token,
|
||||
localMethod: null,
|
||||
MethodFixupSignature.SignatureKind.Signature);
|
||||
_instantiatedMethodImports.Add(method, methodImport);
|
||||
|
@ -717,6 +714,33 @@ namespace ILCompiler.DependencyAnalysis
|
|||
return MethodEntrypoint(method, token, isUnboxingStub);
|
||||
}
|
||||
|
||||
protected override IEETypeNode CreateNecessaryTypeNode(TypeDesc type)
|
||||
{
|
||||
if (CompilationModuleGroup.ContainsType(type))
|
||||
{
|
||||
return new AvailableType(this, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ExternalTypeNode(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEETypeNode CreateConstructedTypeNode(TypeDesc type)
|
||||
{
|
||||
// Canonical definition types are *not* constructed types (call NecessaryTypeSymbol to get them)
|
||||
Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
|
||||
|
||||
if (CompilationModuleGroup.ContainsType(type))
|
||||
{
|
||||
return new AvailableType(this, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ExternalTypeNode(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IMethodNode CreateMethodEntrypointNode(MethodDesc method)
|
||||
{
|
||||
if (!CompilationModuleGroup.ContainsMethodBody(method, unboxingStub: false))
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ILCompiler.DependencyAnalysis;
|
||||
using ILCompiler.DependencyAnalysis.ReadyToRun;
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
|
||||
using Internal.TypeSystem;
|
||||
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
|
||||
namespace ILCompiler
|
||||
{
|
||||
public class ReadyToRunTableManager : MetadataManager
|
||||
{
|
||||
private readonly HashSet<TypeDesc> _typesWithAvailableTypesGenerated = new HashSet<TypeDesc>();
|
||||
|
||||
public ReadyToRunTableManager(CompilerTypeSystemContext typeSystemContext)
|
||||
: base(typeSystemContext, new NoMetadataBlockingPolicy(), new NoManifestResourceBlockingPolicy()) {}
|
||||
|
||||
public override void AddToReadyToRunHeader(ReadyToRunHeaderNode header, NodeFactory nodeFactory, ExternalReferencesTableNode commonFixupsTableNode)
|
||||
{
|
||||
// We don't attach any metadata blobs.
|
||||
}
|
||||
|
||||
protected override void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)
|
||||
{
|
||||
base.Graph_NewMarkedNode(obj);
|
||||
|
||||
var eetypeNode = obj as AvailableType;
|
||||
if (eetypeNode != null)
|
||||
{
|
||||
_typesWithAvailableTypesGenerated.Add(eetypeNode.Type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TypeDesc> GetTypesWithAvailableTypes()
|
||||
{
|
||||
return _typesWithAvailableTypesGenerated;
|
||||
}
|
||||
|
||||
public override MethodDesc GetCanonicalReflectionInvokeStub(MethodDesc method) => throw new NotImplementedException();
|
||||
public override IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata() => throw new NotImplementedException();
|
||||
public override bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method) => throw new NotImplementedException();
|
||||
public override bool WillUseMetadataTokenToReferenceField(FieldDesc field) => throw new NotImplementedException();
|
||||
public override bool WillUseMetadataTokenToReferenceMethod(MethodDesc method) => throw new NotImplementedException();
|
||||
protected override void ComputeMetadata(NodeFactory factory, out byte[] metadataBlob, out List<MetadataMapping<MetadataType>> typeMappings, out List<MetadataMapping<MethodDesc>> methodMappings, out List<MetadataMapping<FieldDesc>> fieldMappings, out List<MetadataMapping<MethodDesc>> stackTraceMapping) => throw new NotImplementedException();
|
||||
protected override MetadataCategory GetMetadataCategory(MethodDesc method) => throw new NotImplementedException();
|
||||
protected override MetadataCategory GetMetadataCategory(TypeDesc type) => throw new NotImplementedException();
|
||||
protected override MetadataCategory GetMetadataCategory(FieldDesc field) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -28,7 +28,9 @@
|
|||
|
||||
<ItemGroup>
|
||||
<Compile Include="CodeGen\ReadyToRunObjectWriter.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ExternalTypeNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ReadyToRunCodegenNodeFactory.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\AvailableType.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\ByteArrayComparer.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\CompilerIdentifierNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DelayLoadHelperImport.cs" />
|
||||
|
@ -72,6 +74,7 @@
|
|||
<Compile Include="Compiler\ReadyToRunMetadataFieldLayoutAlgorithm.cs" />
|
||||
<Compile Include="Compiler\ReadyToRunNodeMangler.cs" />
|
||||
<Compile Include="Compiler\ReadyToRunSingleAssemblyCompilationModuleGroup.cs" />
|
||||
<Compile Include="Compiler\ReadyToRunTableManager.cs" />
|
||||
<Compile Include="JitInterface\CorInfoImpl.ReadyToRun.cs" />
|
||||
<Compile Include="ObjectWriter\SectionBuilder.cs" />
|
||||
<Compile Include="ObjectWriter\R2RPEBuilder.cs" />
|
||||
|
|
|
@ -491,7 +491,16 @@ namespace ILCompiler
|
|||
|
||||
bool supportsReflection = !_isReadyToRunCodeGen && !_isWasmCodegen && !_isCppCodegen && _systemModuleName == DefaultSystemModule;
|
||||
|
||||
MetadataManager compilationMetadataManager = supportsReflection ? metadataManager : (MetadataManager)new EmptyMetadataManager(typeSystemContext);
|
||||
MetadataManager compilationMetadataManager;
|
||||
if (_isReadyToRunCodeGen)
|
||||
{
|
||||
compilationMetadataManager = new ReadyToRunTableManager(typeSystemContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
compilationMetadataManager = supportsReflection ? metadataManager : (MetadataManager)new EmptyMetadataManager(typeSystemContext);
|
||||
}
|
||||
|
||||
ILScanResults scanResults = null;
|
||||
if (useScanner)
|
||||
{
|
||||
|
|
|
@ -261,6 +261,25 @@ internal class Program
|
|||
return true;
|
||||
}
|
||||
|
||||
private static bool CreateLocalClassInstance()
|
||||
{
|
||||
var testClass = new TestClass(1234);
|
||||
Console.WriteLine("Successfully constructed TestClass");
|
||||
return testClass.A == 1234;
|
||||
}
|
||||
|
||||
private class TestClass
|
||||
{
|
||||
private int _a;
|
||||
|
||||
public TestClass(int a)
|
||||
{
|
||||
_a = a;
|
||||
}
|
||||
|
||||
public int A => _a;
|
||||
}
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0)
|
||||
|
@ -290,6 +309,8 @@ internal class Program
|
|||
RunTest("ManipulateListOfString", ManipulateListOfString());
|
||||
|
||||
RunTest("EmptyArray", EmptyArray());
|
||||
RunTest("CreateLocalClassInstance", CreateLocalClassInstance());
|
||||
|
||||
// TODO: RunTest("EnumerateEmptyArray", EnumerateEmptyArray());
|
||||
|
||||
Console.WriteLine($@"{_passedTests.Count} tests pass:");
|
||||
|
|
Загрузка…
Ссылка в новой задаче