Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFadi Hanna <fadim@microsoft.com>2017-10-25 00:39:09 +0300
committerFadi Hanna <fadim@microsoft.com>2017-10-25 00:39:09 +0300
commit27a9c6cf779e7a0424d45e05f8eb589068b67c82 (patch)
tree0d52e3481b177d0451208843ecb91f16805f207a /src/ILCompiler.Compiler
parent789e00c53bf1d0786150ce5d8b6cb3cb0301a9ec (diff)
Adding support for the DefaultConstructorMap hashtable, to enable proper construction of types accessible through lazy generics code.
[tfs-changeset: 1679067]
Diffstat (limited to 'src/ILCompiler.Compiler')
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DefaultConstructorMapNode.cs114
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs42
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs13
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs15
-rw-r--r--src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj1
5 files changed, 182 insertions, 3 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DefaultConstructorMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DefaultConstructorMapNode.cs
new file mode 100644
index 000000000..81e8eb38d
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DefaultConstructorMapNode.cs
@@ -0,0 +1,114 @@
+// 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.Diagnostics;
+using System.Collections.Generic;
+
+using Internal.Text;
+using Internal.TypeSystem;
+using Internal.NativeFormat;
+
+using ILCompiler.DependencyAnalysisFramework;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ /// <summary>
+ /// Dependency analysis node used to keep track of types needing an entry in the default
+ /// constructor map hashtable
+ /// </summary>
+ internal sealed class DefaultConstructorFromLazyNode : DependencyNodeCore<NodeFactory>
+ {
+ public TypeDesc TypeNeedingDefaultCtor { get; }
+
+ public DefaultConstructorFromLazyNode(TypeDesc type)
+ {
+ Debug.Assert(!type.IsRuntimeDeterminedSubtype);
+ Debug.Assert(type == type.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Debug.Assert(type.GetDefaultConstructor() != null && !type.IsValueType);
+
+ TypeNeedingDefaultCtor = type;
+ }
+
+ public override bool HasDynamicDependencies => false;
+ public override bool HasConditionalStaticDependencies => false;
+ public override bool InterestingForDynamicDependencyAnalysis => false;
+ public override bool StaticDependenciesAreComputed => true;
+ protected override string GetName(NodeFactory factory) => "__DefaultConstructorFromLazyNode_" + factory.NameMangler.GetMangledTypeName(TypeNeedingDefaultCtor);
+ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) => null;
+ public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
+
+ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context)
+ {
+ yield return new DependencyListEntry(
+ context.MethodEntrypoint(TypeNeedingDefaultCtor.GetDefaultConstructor(), TypeNeedingDefaultCtor.IsValueType),
+ "DefaultConstructorNode");
+ }
+ }
+
+ /// <summary>
+ /// DefaultConstructorMap blob, containing information on default constructor entrypoints of all types used
+ /// by lazy generic instantiations.
+ /// </summary>
+ internal class DefaultConstructorMapNode : ObjectNode, ISymbolDefinitionNode
+ {
+ private ObjectAndOffsetSymbolNode _endSymbol;
+ private ExternalReferencesTableNode _externalReferences;
+
+ public DefaultConstructorMapNode(ExternalReferencesTableNode externalReferences)
+ {
+ _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__DefaultConstructor_Map_End", true);
+ _externalReferences = externalReferences;
+ }
+
+ public ISymbolNode EndSymbol => _endSymbol;
+
+ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
+ {
+ sb.Append(nameMangler.CompilationUnitPrefix).Append("__DefaultConstructor_Map");
+ }
+
+ public int Offset => 0;
+ public override bool IsShareable => false;
+ public override ObjectNodeSection Section => _externalReferences.Section;
+ public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => false;
+ public override bool StaticDependenciesAreComputed => true;
+ protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
+
+ 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 });
+
+ var writer = new NativeWriter();
+ var defaultConstructorHashtable = new VertexHashtable();
+
+ Section defaultConstructorHashtableSection = writer.NewSection();
+ defaultConstructorHashtableSection.Place(defaultConstructorHashtable);
+
+ foreach (var ctorNeeded in factory.MetadataManager.GetDefaultConstructorsNeeded())
+ {
+ MethodDesc defaultCtor = ctorNeeded.TypeNeedingDefaultCtor.GetDefaultConstructor();
+ Debug.Assert(defaultCtor != null);
+
+ ISymbolNode typeNode = factory.NecessaryTypeSymbol(ctorNeeded.TypeNeedingDefaultCtor);
+ ISymbolNode defaultCtorNode = factory.MethodEntrypoint(defaultCtor, false);
+
+ Vertex vertex = writer.GetTuple(
+ writer.GetUnsignedConstant(_externalReferences.GetIndex(typeNode)),
+ writer.GetUnsignedConstant(_externalReferences.GetIndex(defaultCtorNode)));
+
+ int hashCode = ctorNeeded.TypeNeedingDefaultCtor.GetHashCode();
+ defaultConstructorHashtable.Append((uint)hashCode, defaultConstructorHashtableSection.Place(vertex));
+ }
+
+ byte[] hashTableBytes = writer.Save();
+
+ _endSymbol.SetSymbolOffset(hashTableBytes.Length);
+
+ return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol });
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs
index 6c1f68d4a..8e300741d 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs
@@ -131,7 +131,7 @@ namespace ILCompiler.DependencyAnalysis
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
{
- DependencyList result = result = new DependencyList();
+ DependencyList result = new DependencyList();
result.Add(GetDictionaryLayout(factory), "Layout");
@@ -151,6 +151,21 @@ namespace ILCompiler.DependencyAnalysis
}
}
+ // Lazy generic use of the Activator.CreateInstance<T> heuristic requires tracking type parameters that are used in lazy generics.
+ if (factory.LazyGenericsPolicy.UsesLazyGenerics(_owningType))
+ {
+ foreach (var arg in _owningType.Instantiation)
+ {
+ // Skip types that do not have a default constructor (not interesting).
+ if (arg.IsValueType || arg.GetDefaultConstructor() == null)
+ continue;
+
+ result.Add(new DependencyListEntry(
+ factory.DefaultConstructorFromLazy(arg.ConvertToCanonForm(CanonicalFormKind.Specific)),
+ "Default constructor for lazy generics"));
+ }
+ }
+
return result;
}
@@ -211,6 +226,31 @@ namespace ILCompiler.DependencyAnalysis
factory.InteropStubManager.AddMarshalAPIsGenericDependencies(ref dependencies, factory, _owningMethod);
+ // Lazy generic use of the Activator.CreateInstance<T> heuristic requires tracking type parameters that are used in lazy generics.
+ if (factory.LazyGenericsPolicy.UsesLazyGenerics(_owningMethod))
+ {
+ foreach (var arg in _owningMethod.OwningType.Instantiation)
+ {
+ // Skip types that do not have a default constructor (not interesting).
+ if (arg.IsValueType || arg.GetDefaultConstructor() == null)
+ continue;
+
+ dependencies.Add(new DependencyListEntry(
+ factory.DefaultConstructorFromLazy(arg.ConvertToCanonForm(CanonicalFormKind.Specific)),
+ "Default constructor for lazy generics"));
+ }
+ foreach (var arg in _owningMethod.Instantiation)
+ {
+ // Skip types that do not have a default constructor (not interesting).
+ if (arg.IsValueType || arg.GetDefaultConstructor() == null)
+ continue;
+
+ dependencies.Add(new DependencyListEntry(
+ factory.DefaultConstructorFromLazy(arg.ConvertToCanonForm(CanonicalFormKind.Specific)),
+ "Default constructor for lazy generics"));
+ }
+ }
+
return dependencies;
}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs
index 6d267094e..978d5a5db 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs
@@ -483,6 +483,11 @@ namespace ILCompiler.DependencyAnalysis
return new StringAllocatorMethodNode(constructor);
});
+ _defaultConstructorFromLazyNodes = new NodeCache<TypeDesc, DefaultConstructorFromLazyNode>(type =>
+ {
+ return new DefaultConstructorFromLazyNode(type);
+ });
+
NativeLayout = new NativeLayoutHelper(this);
WindowsDebugData = new WindowsDebugDataHelper(this);
}
@@ -781,19 +786,23 @@ namespace ILCompiler.DependencyAnalysis
}
private NodeCache<MethodKey, IMethodNode> _shadowConcreteMethods;
-
public IMethodNode ShadowConcreteMethod(MethodDesc method, bool isUnboxingStub = false)
{
return _shadowConcreteMethods.GetOrAdd(new MethodKey(method, isUnboxingStub));
}
private NodeCache<MethodDesc, IMethodNode> _runtimeDeterminedMethods;
-
public IMethodNode RuntimeDeterminedMethod(MethodDesc method)
{
return _runtimeDeterminedMethods.GetOrAdd(method);
}
+ private NodeCache<TypeDesc, DefaultConstructorFromLazyNode> _defaultConstructorFromLazyNodes;
+ internal DefaultConstructorFromLazyNode DefaultConstructorFromLazy(TypeDesc type)
+ {
+ return _defaultConstructorFromLazyNodes.GetOrAdd(type);
+ }
+
private static readonly string[][] s_helperEntrypointNames = new string[][] {
new string[] { "System.Runtime.CompilerServices", "ClassConstructorRunner", "CheckStaticClassConstructionReturnGCStaticBase" },
new string[] { "System.Runtime.CompilerServices", "ClassConstructorRunner", "CheckStaticClassConstructionReturnNonGCStaticBase" },
diff --git a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
index 23eaac139..818c040f4 100644
--- a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
@@ -45,6 +45,7 @@ namespace ILCompiler
private HashSet<IMethodBodyNode> _methodBodiesGenerated = new HashSet<IMethodBodyNode>();
private List<ModuleDesc> _modulesWithMetadata = new List<ModuleDesc>();
private List<TypeGVMEntriesNode> _typeGVMEntries = new List<TypeGVMEntriesNode>();
+ private HashSet<DefaultConstructorFromLazyNode> _defaultConstructorsNeeded = new HashSet<DefaultConstructorFromLazyNode>();
internal NativeLayoutInfoNode NativeLayoutInfo { get; private set; }
internal DynamicInvokeTemplateDataNode DynamicInvokeTemplateData { get; private set; }
@@ -135,6 +136,9 @@ namespace ILCompiler
var virtualInvokeMapNode = new ReflectionVirtualInvokeMapNode(commonFixupsTableNode);
header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.VirtualInvokeMap), virtualInvokeMapNode, virtualInvokeMapNode, virtualInvokeMapNode.EndSymbol);
+ var defaultConstructorMapNode = new DefaultConstructorMapNode(commonFixupsTableNode);
+ header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.DefaultConstructorMap), defaultConstructorMapNode, defaultConstructorMapNode, defaultConstructorMapNode.EndSymbol);
+
// The external references tables should go last
header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.CommonFixupsTable), commonFixupsTableNode, commonFixupsTableNode, commonFixupsTableNode.EndSymbol);
header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.NativeReferences), nativeReferencesTableNode, nativeReferencesTableNode, nativeReferencesTableNode.EndSymbol);
@@ -199,6 +203,12 @@ namespace ILCompiler
_genericDictionariesGenerated.Add(dictionaryNode);
}
+ var ctorFromLazyGenericsNode = obj as DefaultConstructorFromLazyNode;
+ if (ctorFromLazyGenericsNode != null)
+ {
+ _defaultConstructorsNeeded.Add(ctorFromLazyGenericsNode);
+ }
+
// TODO: temporary until we have an IL scanning Metadata Manager. We shouldn't have to keep track of these.
var moduleMetadataNode = obj as ModuleMetadataNode;
if (moduleMetadataNode != null)
@@ -570,6 +580,11 @@ namespace ILCompiler
return _methodBodiesGenerated;
}
+ internal IEnumerable<DefaultConstructorFromLazyNode> GetDefaultConstructorsNeeded()
+ {
+ return _defaultConstructorsNeeded;
+ }
+
internal bool TypeGeneratesEEType(TypeDesc type)
{
return _typesWithEETypesGenerated.Contains(type);
diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
index 1f95fd8d7..86c3983c2 100644
--- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
+++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
@@ -103,6 +103,7 @@
<Compile Include="Compiler\CompilerTypeSystemContext.Sorting.cs" />
<Compile Include="Compiler\CompilerGeneratedInteropStubManager.cs" />
<Compile Include="Compiler\DebugInformationProvider.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\DefaultConstructorMapNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugILImagesSection.cs" />
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugManagedNativeDictionaryInfoSection.cs" />
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugMergedAssemblyRecordsSection.cs" />