diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 26b0c703d..1a2c8e435 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -149,60 +149,18 @@ namespace ILCompiler.DependencyAnalysis { return _cache.GetOrAdd(key, _creator); } + + public TValue GetOrAdd(TKey key, Func creator) + { + return _cache.GetOrAdd(key, creator); + } } private void CreateNodeCaches() { - _typeSymbols = new NodeCache((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(CreateNecessaryTypeNode); - _constructedTypeSymbols = new NodeCache((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(CreateConstructedTypeNode); _clonedTypeSymbols = new NodeCache((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 _methodEntrypoints; + protected NodeCache _methodEntrypoints; private NodeCache _unboxingStubs; private NodeCache _methodAssociatedData; diff --git a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs index de1994958..9771d87da 100644 --- a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs +++ b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs @@ -45,8 +45,8 @@ namespace ILCompiler protected readonly ManifestResourceBlockingPolicy _resourceBlockingPolicy; private List _cctorContextsGenerated = new List(); - private HashSet _typesWithEETypesGenerated = new HashSet(); - private HashSet _typesWithConstructedEETypesGenerated = new HashSet(); + private readonly HashSet _typesWithEETypesGenerated = new HashSet(); + private readonly HashSet _typesWithConstructedEETypesGenerated = new HashSet(); private HashSet _methodsGenerated = new HashSet(); private HashSet _genericDictionariesGenerated = new HashSet(); private HashSet _methodBodiesGenerated = new HashSet(); @@ -560,7 +560,7 @@ namespace ILCompiler return _genericDictionariesGenerated; } - internal IEnumerable GetCompiledMethods() + public IEnumerable GetCompiledMethods() { return _methodsGenerated; } diff --git a/src/ILCompiler.ReadyToRun/src/CodeGen/ReadyToRunObjectWriter.cs b/src/ILCompiler.ReadyToRun/src/CodeGen/ReadyToRunObjectWriter.cs index 36c87fde7..a45b8f1ca 100644 --- a/src/ILCompiler.ReadyToRun/src/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/ILCompiler.ReadyToRun/src/CodeGen/ReadyToRunObjectWriter.cs @@ -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) { diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ExternalTypeNode.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ExternalTypeNode.cs new file mode 100644 index 000000000..389d56242 --- /dev/null +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ExternalTypeNode.cs @@ -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, 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 GetConditionalStaticDependencies(NodeFactory context) => null; + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory context) => null; + public override IEnumerable GetStaticDependencies(NodeFactory context) => null; + + protected override string GetName(NodeFactory factory) => $"Externally referenced type {Type.ToString()}"; + } +} diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/AvailableType.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/AvailableType.cs new file mode 100644 index 000000000..5651dad36 --- /dev/null +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/AvailableType.cs @@ -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, 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 GetConditionalStaticDependencies(NodeFactory context) => null; + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory context) => null; + public override IEnumerable GetStaticDependencies(NodeFactory context) => null; + + protected override string GetName(NodeFactory factory) => $"Available type {Type.ToString()}"; + } +} diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs index e5e3fe492..190fdd86e 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/ExternalMethodImport.cs @@ -32,6 +32,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun } public MethodDesc Method => _methodDesc; + public MethodWithGCInfo MethodCodeNode => _localMethod; public override int ClassCode => 458823351; diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodEntryPointTableNode.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodEntryPointTableNode.cs index e12faf07e..c82c21f5c 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodEntryPointTableNode.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodEntryPointTableNode.cs @@ -66,7 +66,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun } } - List _ridToEntryPoint; + private List _ridToEntryPoint; public MethodEntryPointTableNode(TargetDetails target) : base(target) @@ -200,6 +200,19 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun return new ObjectData(Array.Empty(), Array.Empty(), 1, Array.Empty()); } + 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(); diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs index 6832ed0b5..86938f476 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs @@ -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) diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs index ec3ef6dd2..5e313b497 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewArrayFixupSignature.cs @@ -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; + } } } diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.cs index 9d6244f27..fbcff9973 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/NewObjectFixupSignature.cs @@ -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; + } } } diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/RuntimeFunctionsTableNode.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/RuntimeFunctionsTableNode.cs index 09685df7e..0f864619b 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/RuntimeFunctionsTableNode.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/RuntimeFunctionsTableNode.cs @@ -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 _methodNodes; + private List _methodNodes; + private Dictionary _insertedMethodNodes; + private readonly NodeFactory _nodeFactory; - public RuntimeFunctionsTableNode(TargetDetails target) - : base(target) + public RuntimeFunctionsTableNode(NodeFactory nodeFactory) + : base(nodeFactory.Target) { - _methodNodes = new List(); + _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(); + _insertedMethodNodes = new Dictionary(); + + 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(), Array.Empty(), 1, new ISymbolDefinitionNode[] { this }); + + if (_methodNodes == null) + LayoutRuntimeFunctions(); + ObjectDataBuilder runtimeFunctionsBuilder = new ObjectDataBuilder(factory, relocsOnly); // Add the symbol representing this object node diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs index 36460aa3b..3cc4d3433 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs @@ -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; + } } } diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypesTableNode.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypesTableNode.cs index 3d2aa8773..9216e3448 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypesTableNode.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRun/TypesTableNode.cs @@ -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(), Array.Empty(), 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(); diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index b1d1e8efa..021882bf9 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -26,12 +26,12 @@ namespace ILCompiler.DependencyAnalysis private Dictionary _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 _methodMap = new Dictionary(); - 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)) diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunTableManager.cs b/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunTableManager.cs new file mode 100644 index 000000000..0ecb562bb --- /dev/null +++ b/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunTableManager.cs @@ -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 _typesWithAvailableTypesGenerated = new HashSet(); + + 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 obj) + { + base.Graph_NewMarkedNode(obj); + + var eetypeNode = obj as AvailableType; + if (eetypeNode != null) + { + _typesWithAvailableTypesGenerated.Add(eetypeNode.Type); + return; + } + } + + public IEnumerable GetTypesWithAvailableTypes() + { + return _typesWithAvailableTypesGenerated; + } + + public override MethodDesc GetCanonicalReflectionInvokeStub(MethodDesc method) => throw new NotImplementedException(); + public override IEnumerable 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> typeMappings, out List> methodMappings, out List> fieldMappings, out List> 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(); + } +} diff --git a/src/ILCompiler.ReadyToRun/src/ILCompiler.ReadyToRun.csproj b/src/ILCompiler.ReadyToRun/src/ILCompiler.ReadyToRun.csproj index 4360c1ecd..b17c2c8fd 100644 --- a/src/ILCompiler.ReadyToRun/src/ILCompiler.ReadyToRun.csproj +++ b/src/ILCompiler.ReadyToRun/src/ILCompiler.ReadyToRun.csproj @@ -28,7 +28,9 @@ + + @@ -72,6 +74,7 @@ + diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs index 1fcdc1201..372ef70b7 100644 --- a/src/ILCompiler/src/Program.cs +++ b/src/ILCompiler/src/Program.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) { diff --git a/tests/src/Simple/ReadyToRunUnit/Program.cs b/tests/src/Simple/ReadyToRunUnit/Program.cs index 99fc25443..0c442dc1e 100644 --- a/tests/src/Simple/ReadyToRunUnit/Program.cs +++ b/tests/src/Simple/ReadyToRunUnit/Program.cs @@ -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:");