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:
authorMichal Strehovský <michals@microsoft.com>2017-12-17 17:55:09 +0300
committerMichal Strehovský <michals@microsoft.com>2017-12-18 14:29:13 +0300
commitea415ea2ce856e50c5ca61c52e8153af48c2e928 (patch)
treeedf33d40970a44a3fbe886a91f57f32dfbee0f89
parent243c3ef555f525550317f834dd4a8aac8ccfcb66 (diff)
Add AnalysisBasedMetadataManager
This takes a collection of types/methods/fields that need to be generated into the image (both metadata and runtime artifacts) and ensures the runtime artifacts are generated, along with the metadata.
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs254
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs10
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/ILScannerBuilder.cs12
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs27
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/UsageBasedMetadataManager.cs179
-rw-r--r--src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj1
-rw-r--r--src/ILCompiler/src/Program.cs28
7 files changed, 470 insertions, 41 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs
new file mode 100644
index 000000000..a9cd21190
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs
@@ -0,0 +1,254 @@
+// 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 Internal.TypeSystem;
+
+using ILCompiler.Metadata;
+using ILCompiler.DependencyAnalysis;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler
+{
+ /// <summary>
+ /// A metadata manager that knows the full set of metadata ahead of time.
+ /// </summary>
+ public sealed class AnalysisBasedMetadataManager : GeneratingMetadataManager, ICompilationRootProvider
+ {
+ private readonly List<ModuleDesc> _modulesWithMetadata;
+
+ private readonly Dictionary<TypeDesc, MetadataCategory> _reflectableTypes = new Dictionary<TypeDesc, MetadataCategory>();
+ private readonly Dictionary<MethodDesc, MetadataCategory> _reflectableMethods = new Dictionary<MethodDesc, MetadataCategory>();
+ private readonly Dictionary<FieldDesc, MetadataCategory> _reflectableFields = new Dictionary<FieldDesc, MetadataCategory>();
+
+ public AnalysisBasedMetadataManager(
+ ModuleDesc generatedAssembly,
+ CompilerTypeSystemContext typeSystemContext,
+ MetadataBlockingPolicy blockingPolicy,
+ string logFile,
+ StackTraceEmissionPolicy stackTracePolicy,
+ IEnumerable<ModuleDesc> modulesWithMetadata,
+ IEnumerable<ReflectableEntity<TypeDesc>> reflectableTypes,
+ IEnumerable<ReflectableEntity<MethodDesc>> reflectableMethods,
+ IEnumerable<ReflectableEntity<FieldDesc>> reflectableFields)
+ : base(generatedAssembly, typeSystemContext, blockingPolicy, logFile, stackTracePolicy)
+ {
+ _modulesWithMetadata = new List<ModuleDesc>(modulesWithMetadata);
+
+ foreach (var refType in reflectableTypes)
+ {
+ _reflectableTypes.Add(refType.Entity, refType.Category);
+ }
+
+ foreach (var refMethod in reflectableMethods)
+ {
+ // Asking for description or runtime mapping for a member without asking
+ // for the owning type would mean we can't actually satisfy the request.
+ Debug.Assert((refMethod.Category & MetadataCategory.Description) == 0
+ || (_reflectableTypes[refMethod.Entity.OwningType] & MetadataCategory.Description) != 0);
+ Debug.Assert((refMethod.Category & MetadataCategory.RuntimeMapping) == 0
+ || (_reflectableTypes[refMethod.Entity.OwningType] & MetadataCategory.RuntimeMapping) != 0);
+ _reflectableMethods.Add(refMethod.Entity, refMethod.Category);
+
+ MethodDesc canonMethod = refMethod.Entity.GetCanonMethodTarget(CanonicalFormKind.Specific);
+ if (refMethod.Entity != canonMethod)
+ {
+ if (!_reflectableMethods.TryGetValue(canonMethod, out MetadataCategory category))
+ category = 0;
+ _reflectableMethods[canonMethod] = category | refMethod.Category;
+ }
+ }
+
+ foreach (var refField in reflectableFields)
+ {
+ // Asking for description or runtime mapping for a member without asking
+ // for the owning type would mean we can't actually satisfy the request.
+ Debug.Assert((refField.Category & MetadataCategory.Description) == 0
+ || (_reflectableTypes[refField.Entity.OwningType] & MetadataCategory.Description) != 0);
+ Debug.Assert((refField.Category & MetadataCategory.RuntimeMapping) == 0
+ || (_reflectableTypes[refField.Entity.OwningType] & MetadataCategory.RuntimeMapping) != 0);
+ _reflectableFields.Add(refField.Entity, refField.Category);
+ }
+
+#if DEBUG
+ HashSet<ModuleDesc> moduleHash = new HashSet<ModuleDesc>(_modulesWithMetadata);
+ foreach (var refType in reflectableTypes)
+ {
+ // The instantiated types need to agree on the Description bit with the definition.
+ // GetMetadataCategory relies on that.
+ Debug.Assert((GetMetadataCategory(refType.Entity.GetTypeDefinition()) & MetadataCategory.Description)
+ == (GetMetadataCategory(refType.Entity) & MetadataCategory.Description));
+
+ Debug.Assert(!(refType.Entity is MetadataType) || moduleHash.Contains(((MetadataType)refType.Entity).Module));
+ }
+
+ foreach (var refMethod in reflectableMethods)
+ {
+ // The instantiated methods need to agree on the Description bit with the definition.
+ // GetMetadataCategory relies on that.
+ Debug.Assert((GetMetadataCategory(refMethod.Entity.GetTypicalMethodDefinition()) & MetadataCategory.Description)
+ == (GetMetadataCategory(refMethod.Entity) & MetadataCategory.Description));
+ }
+
+ foreach (var refField in reflectableFields)
+ {
+ // The instantiated fields need to agree on the Description bit with the definition.
+ // GetMetadataCategory relies on that.
+ Debug.Assert((GetMetadataCategory(refField.Entity.GetTypicalFieldDefinition()) & MetadataCategory.Description)
+ == (GetMetadataCategory(refField.Entity) & MetadataCategory.Description));
+ }
+#endif
+ }
+
+ public override IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata()
+ {
+ return _modulesWithMetadata;
+ }
+
+ 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)
+ {
+ ComputeMetadata(new Policy(_blockingPolicy, this), factory,
+ out metadataBlob,
+ out typeMappings,
+ out methodMappings,
+ out fieldMappings,
+ out stackTraceMapping);
+ }
+
+ protected sealed override MetadataCategory GetMetadataCategory(MethodDesc method)
+ {
+ if (_reflectableMethods.TryGetValue(method, out MetadataCategory value))
+ return value;
+ return 0;
+ }
+
+ protected sealed override MetadataCategory GetMetadataCategory(TypeDesc type)
+ {
+ if (_reflectableTypes.TryGetValue(type, out MetadataCategory value))
+ return value;
+ return 0;
+ }
+
+ protected sealed override MetadataCategory GetMetadataCategory(FieldDesc field)
+ {
+ if (_reflectableFields.TryGetValue(field, out MetadataCategory value))
+ return value;
+ return 0;
+ }
+
+ void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider)
+ {
+ // We go over all the types and members that need a runtime artiface present in the
+ // compiled executable and root it.
+
+ const string reason = "Reflection";
+
+ foreach (var pair in _reflectableTypes)
+ {
+ if ((pair.Value & MetadataCategory.RuntimeMapping) != 0)
+ rootProvider.AddCompilationRoot(pair.Key, reason);
+ }
+
+ foreach (var pair in _reflectableMethods)
+ {
+ if ((pair.Value & MetadataCategory.RuntimeMapping) != 0)
+ {
+ MethodDesc method = pair.Key;
+
+ // We need to root virtual methods as if they were called virtually.
+ // This will possibly trigger the generation of other overrides too.
+ if (method.IsVirtual)
+ rootProvider.RootVirtualMethodForReflection(method, reason);
+
+ if (!method.IsAbstract)
+ rootProvider.AddCompilationRoot(pair.Key, reason);
+ }
+ }
+
+ foreach (var pair in _reflectableFields)
+ {
+ if ((pair.Value & MetadataCategory.RuntimeMapping) != 0)
+ {
+ FieldDesc field = pair.Key;
+
+ // We only care about static fields at this point. Instance fields don't need
+ // runtime artifacts generated in the image.
+ if (field.IsStatic && !field.IsLiteral)
+ {
+ if (field.IsThreadStatic)
+ rootProvider.RootThreadStaticBaseForType(field.OwningType, reason);
+ else if (field.HasGCStaticBase)
+ rootProvider.RootGCStaticBaseForType(field.OwningType, reason);
+ else
+ rootProvider.RootNonGCStaticBaseForType(field.OwningType, reason);
+ }
+ }
+ }
+ }
+
+ private struct Policy : IMetadataPolicy
+ {
+ private readonly MetadataBlockingPolicy _blockingPolicy;
+ private readonly ExplicitScopeAssemblyPolicyMixin _explicitScopeMixin;
+ private readonly AnalysisBasedMetadataManager _parent;
+
+ public Policy(MetadataBlockingPolicy blockingPolicy,
+ AnalysisBasedMetadataManager parent)
+ {
+ _blockingPolicy = blockingPolicy;
+ _parent = parent;
+ _explicitScopeMixin = new ExplicitScopeAssemblyPolicyMixin();
+ }
+
+ public bool GeneratesMetadata(FieldDesc fieldDef)
+ {
+ return (_parent.GetMetadataCategory(fieldDef) & MetadataCategory.Description) != 0;
+ }
+
+ public bool GeneratesMetadata(MethodDesc methodDef)
+ {
+ return (_parent.GetMetadataCategory(methodDef) & MetadataCategory.Description) != 0;
+ }
+
+ public bool GeneratesMetadata(MetadataType typeDef)
+ {
+ return (_parent.GetMetadataCategory(typeDef) & MetadataCategory.Description) != 0;
+ }
+
+ public bool IsBlocked(MetadataType typeDef)
+ {
+ return _blockingPolicy.IsBlocked(typeDef);
+ }
+
+ public bool IsBlocked(MethodDesc methodDef)
+ {
+ return _blockingPolicy.IsBlocked(methodDef);
+ }
+
+ public ModuleDesc GetModuleOfType(MetadataType typeDef)
+ {
+ return _explicitScopeMixin.GetModuleOfType(typeDef);
+ }
+ }
+ }
+
+ public struct ReflectableEntity<TEntity>
+ {
+ public readonly TEntity Entity;
+ public readonly MetadataCategory Category;
+
+ public ReflectableEntity(TEntity entity, MetadataCategory category)
+ {
+ Entity = entity;
+ Category = category;
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs
index 50efd7c6d..e9270da0e 100644
--- a/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs
@@ -24,8 +24,8 @@ namespace ILCompiler
/// </summary>
public abstract class GeneratingMetadataManager : MetadataManager
{
- private readonly string _metadataLogFile;
- private readonly StackTraceEmissionPolicy _stackTraceEmissionPolicy;
+ protected readonly string _metadataLogFile;
+ protected readonly StackTraceEmissionPolicy _stackTraceEmissionPolicy;
private readonly Dictionary<DynamicInvokeMethodSignature, MethodDesc> _dynamicInvokeThunks;
private readonly ModuleDesc _generatedAssembly;
@@ -83,7 +83,8 @@ namespace ILCompiler
// Methods that will end up in the reflection invoke table should not have an entry in stack trace table
// We'll try looking them up in reflection data at runtime.
if (transformed.GetTransformedMethodDefinition(typicalMethod) != null &&
- ShouldMethodBeInInvokeMap(method))
+ ShouldMethodBeInInvokeMap(method) &&
+ (GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) != 0)
continue;
if (!_stackTraceEmissionPolicy.ShouldIncludeMethod(method))
@@ -164,6 +165,9 @@ namespace ILCompiler
if (IsReflectionBlocked(method.Instantiation) || IsReflectionBlocked(method.OwningType.Instantiation))
continue;
+ if ((GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) == 0)
+ continue;
+
MetadataRecord record = transformed.GetTransformedMethodDefinition(method.GetTypicalMethodDefinition());
if (record != null)
diff --git a/src/ILCompiler.Compiler/src/Compiler/ILScannerBuilder.cs b/src/ILCompiler.Compiler/src/Compiler/ILScannerBuilder.cs
index 86ee40cd0..340c5603a 100644
--- a/src/ILCompiler.Compiler/src/Compiler/ILScannerBuilder.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/ILScannerBuilder.cs
@@ -23,12 +23,14 @@ namespace ILCompiler
private Logger _logger = Logger.Null;
private DependencyTrackingLevel _dependencyTrackingLevel = DependencyTrackingLevel.None;
private IEnumerable<ICompilationRootProvider> _compilationRoots = Array.Empty<ICompilationRootProvider>();
+ private MetadataManager _metadataManager;
internal ILScannerBuilder(CompilerTypeSystemContext context, CompilationModuleGroup compilationGroup, NameMangler mangler)
{
_context = context;
_compilationGroup = compilationGroup;
_nameMangler = mangler;
+ _metadataManager = new EmptyMetadataManager(context);
}
public ILScannerBuilder UseDependencyTracking(DependencyTrackingLevel trackingLevel)
@@ -43,12 +45,16 @@ namespace ILCompiler
return this;
}
+ public ILScannerBuilder UseMetadataManager(MetadataManager metadataManager)
+ {
+ _metadataManager = metadataManager;
+ return this;
+ }
+
public IILScanner ToILScanner()
{
- // TODO: we will want different metadata managers depending on whether we're doing reflection analysis
- var metadataManager = new UsageBasedMetadataManager(_compilationGroup, _context, new BlockedInternalsBlockingPolicy(), null, new NoStackTraceEmissionPolicy());
var interopStubManager = new CompilerGeneratedInteropStubManager(_compilationGroup, _context, new InteropStateManager(_compilationGroup.GeneratedAssembly));
- var nodeFactory = new ILScanNodeFactory(_context, _compilationGroup, metadataManager, interopStubManager, _nameMangler);
+ var nodeFactory = new ILScanNodeFactory(_context, _compilationGroup, _metadataManager, interopStubManager, _nameMangler);
DependencyAnalyzerBase<NodeFactory> graph = _dependencyTrackingLevel.CreateDependencyGraph(nodeFactory);
return new ILScanner(graph, nodeFactory, _compilationRoots, new NullDebugInformationProvider(), _logger);
diff --git a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
index e6114ad6f..237e850ab 100644
--- a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
@@ -3,12 +3,10 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.IO;
using System.Collections.Generic;
using Internal.TypeSystem;
-using ILCompiler.Metadata;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
@@ -43,7 +41,6 @@ namespace ILCompiler
private HashSet<MethodDesc> _methodsGenerated = new HashSet<MethodDesc>();
private HashSet<GenericDictionaryNode> _genericDictionariesGenerated = new HashSet<GenericDictionaryNode>();
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>();
@@ -152,7 +149,7 @@ namespace ILCompiler
header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.NativeStatics), nativeStaticsTableNode, nativeStaticsTableNode, nativeStaticsTableNode.EndSymbol);
}
- private void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)
+ protected virtual void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)
{
var eetypeNode = obj as EETypeNode;
if (eetypeNode != null)
@@ -173,13 +170,10 @@ namespace ILCompiler
_methodBodiesGenerated.Add(methodBodyNode);
}
- IMethodNode methodNode = obj as MethodCodeNode;
+ IMethodNode methodNode = methodBodyNode;
if (methodNode == null)
methodNode = obj as ShadowConcreteMethodNode;
- if (methodNode == null)
- methodNode = obj as NonExternMethodSymbolNode;
-
if (methodNode != null)
{
_methodsGenerated.Add(methodNode.Method);
@@ -215,13 +209,6 @@ namespace ILCompiler
{
_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)
- {
- _modulesWithMetadata.Add(moduleMetadataNode.Module);
- }
}
/// <summary>
@@ -545,15 +532,7 @@ namespace ILCompiler
/// <summary>
/// Returns a set of modules that will get some metadata emitted into the output module
/// </summary>
- public virtual IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata()
- {
- // TODO: this is temporary until we have a metadata manager for IL scanner. This method should be abstract.
-
- // TODO: We should also return the list of satellite assemblies here (this API is used by the ResourceDataNode to
- // generate the BlobIdResourceIndex blob, for the ResourceManager to work at runtime).
-
- return _modulesWithMetadata;
- }
+ public abstract IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata();
public byte[] GetMetadataBlob(NodeFactory factory)
{
diff --git a/src/ILCompiler.Compiler/src/Compiler/UsageBasedMetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/UsageBasedMetadataManager.cs
index fdb813df8..454432b9b 100644
--- a/src/ILCompiler.Compiler/src/Compiler/UsageBasedMetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/UsageBasedMetadataManager.cs
@@ -8,6 +8,7 @@ using Internal.TypeSystem;
using ILCompiler.Metadata;
using ILCompiler.DependencyAnalysis;
+using ILCompiler.DependencyAnalysisFramework;
using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
@@ -21,6 +22,11 @@ namespace ILCompiler
{
private readonly CompilationModuleGroup _compilationModuleGroup;
+ private readonly List<ModuleDesc> _modulesWithMetadata = new List<ModuleDesc>();
+ private readonly List<FieldDesc> _fieldsWithMetadata = new List<FieldDesc>();
+ private readonly List<MethodDesc> _methodsWithMetadata = new List<MethodDesc>();
+ private readonly List<MetadataType> _typesWithMetadata = new List<MetadataType>();
+
public UsageBasedMetadataManager(
CompilationModuleGroup group,
CompilerTypeSystemContext typeSystemContext,
@@ -32,6 +38,35 @@ namespace ILCompiler
_compilationModuleGroup = group;
}
+ protected override void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)
+ {
+ base.Graph_NewMarkedNode(obj);
+
+ var moduleMetadataNode = obj as ModuleMetadataNode;
+ if (moduleMetadataNode != null)
+ {
+ _modulesWithMetadata.Add(moduleMetadataNode.Module);
+ }
+
+ var fieldMetadataNode = obj as FieldMetadataNode;
+ if (fieldMetadataNode != null)
+ {
+ _fieldsWithMetadata.Add(fieldMetadataNode.Field);
+ }
+
+ var methodMetadataNode = obj as MethodMetadataNode;
+ if (methodMetadataNode != null)
+ {
+ _methodsWithMetadata.Add(methodMetadataNode.Method);
+ }
+
+ var typeMetadataNode = obj as TypeMetadataNode;
+ if (typeMetadataNode != null)
+ {
+ _typesWithMetadata.Add(typeMetadataNode.Type);
+ }
+ }
+
protected override MetadataCategory GetMetadataCategory(FieldDesc field)
{
MetadataCategory category = 0;
@@ -90,15 +125,159 @@ namespace ILCompiler
protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
{
+ if (method.GetTypicalMethodDefinition().OwningType == factory.ArrayOfTClass)
+ return;
+
dependencies = dependencies ?? new DependencyList();
dependencies.Add(factory.MethodMetadata(method.GetTypicalMethodDefinition()), "Reflectable method");
}
protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
+ if (type.GetTypeDefinition() == factory.ArrayOfTClass)
+ return;
+
TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, type, "Reflectable type");
}
+ public override IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata()
+ {
+ return _modulesWithMetadata;
+ }
+
+ public MetadataManager ToAnalysisBasedMetadataManager()
+ {
+ var reflectableTypes = ReflectableEntityBuilder<TypeDesc>.Create();
+
+ // Collect the list of types that are generating reflection metadata
+ foreach (var typeWithMetadata in _typesWithMetadata)
+ {
+ reflectableTypes[typeWithMetadata] = MetadataCategory.Description;
+ }
+
+ // All the constructed types we generated that are not blocked are required to have runtime artifacts
+ foreach (var constructedType in GetTypesWithConstructedEETypes())
+ {
+ if (!IsReflectionBlocked(constructedType))
+ {
+ reflectableTypes[constructedType] |= MetadataCategory.RuntimeMapping;
+
+ // Also set the description bit if the definition is getting metadata.
+ TypeDesc constructedTypeDefinition = constructedType.GetTypeDefinition();
+ if (constructedType != constructedTypeDefinition &&
+ (reflectableTypes[constructedTypeDefinition] & MetadataCategory.Description) != 0)
+ {
+ reflectableTypes[constructedType] |= MetadataCategory.Description;
+ }
+ }
+ }
+
+ // All the necessary types for which this is the higest load level are required to have runtime artifacts
+ foreach (var necessaryType in GetTypesWithEETypes())
+ {
+ if (!ConstructedEETypeNode.CreationAllowed(necessaryType) &&
+ !IsReflectionBlocked(necessaryType))
+ {
+ reflectableTypes[necessaryType] |= MetadataCategory.RuntimeMapping;
+
+ // Also set the description bit if the definition is getting metadata.
+ TypeDesc necessaryTypeDefinition = necessaryType.GetTypeDefinition();
+ if (necessaryType != necessaryTypeDefinition &&
+ (reflectableTypes[necessaryTypeDefinition] & MetadataCategory.Description) != 0)
+ {
+ reflectableTypes[necessaryType] |= MetadataCategory.Description;
+ }
+ }
+ }
+
+ var reflectableMethods = ReflectableEntityBuilder<MethodDesc>.Create();
+ foreach (var methodWithMetadata in _methodsWithMetadata)
+ {
+ reflectableMethods[methodWithMetadata] = MetadataCategory.Description;
+ }
+
+ foreach (var method in GetCompiledMethods())
+ {
+ if (!method.IsCanonicalMethod(CanonicalFormKind.Specific) &&
+ !IsReflectionBlocked(method))
+ {
+ if ((reflectableTypes[method.OwningType] & MetadataCategory.RuntimeMapping) != 0)
+ reflectableMethods[method] |= MetadataCategory.RuntimeMapping;
+
+ // Also set the description bit if the definition is getting metadata.
+ MethodDesc typicalMethod = method.GetTypicalMethodDefinition();
+ if (method != typicalMethod &&
+ (reflectableMethods[typicalMethod] & MetadataCategory.Description) != 0)
+ {
+ reflectableMethods[method] |= MetadataCategory.Description;
+ reflectableTypes[method.OwningType] |= MetadataCategory.Description;
+ }
+ }
+ }
+
+ var reflectableFields = ReflectableEntityBuilder<FieldDesc>.Create();
+ foreach (var fieldWithMetadata in _fieldsWithMetadata)
+ {
+ reflectableFields[fieldWithMetadata] = MetadataCategory.Description;
+ }
+
+ // TODO: this should be more precise
+ foreach (var reflectableType in reflectableTypes.ToEnumerable())
+ {
+ if (reflectableType.Entity.IsGenericDefinition)
+ continue;
+
+ if (reflectableType.Entity.IsCanonicalSubtype(CanonicalFormKind.Specific))
+ continue;
+
+ foreach (var field in reflectableType.Entity.GetFields())
+ {
+ if (CanGenerateMetadata(field.GetTypicalFieldDefinition()))
+ reflectableFields[field] |= reflectableType.Category;
+ }
+ }
+
+ return new AnalysisBasedMetadataManager(_compilationModuleGroup.GeneratedAssembly,
+ _typeSystemContext, _blockingPolicy, _metadataLogFile, _stackTraceEmissionPolicy,
+ _modulesWithMetadata, reflectableTypes.ToEnumerable(), reflectableMethods.ToEnumerable(),
+ reflectableFields.ToEnumerable());
+ }
+
+ private struct ReflectableEntityBuilder<T>
+ {
+ private Dictionary<T, MetadataCategory> _dictionary;
+
+ public static ReflectableEntityBuilder<T> Create()
+ {
+ return new ReflectableEntityBuilder<T>
+ {
+ _dictionary = new Dictionary<T, MetadataCategory>(),
+ };
+ }
+
+ public MetadataCategory this[T key]
+ {
+ get
+ {
+ if (_dictionary.TryGetValue(key, out MetadataCategory category))
+ return category;
+ return 0;
+ }
+ set
+ {
+ _dictionary[key] = value;
+ }
+ }
+
+ public IEnumerable<ReflectableEntity<T>> ToEnumerable()
+ {
+ foreach (var entry in _dictionary)
+ {
+ yield return new ReflectableEntity<T>(entry.Key, entry.Value);
+ }
+ }
+ }
+
private struct GeneratedTypesAndCodeMetadataPolicy : IMetadataPolicy
{
private readonly MetadataBlockingPolicy _blockingPolicy;
diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
index febe21611..7df0a8e4d 100644
--- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
+++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
@@ -97,6 +97,7 @@
<Compile Include="..\..\JitInterface\src\TypeString.cs">
<Link>JitInterface\TypeString.cs</Link>
</Compile>
+ <Compile Include="Compiler\AnalysisBasedMetadataManager.cs" />
<Compile Include="Compiler\BlockedInternalsBlockingPolicy.cs" />
<Compile Include="Compiler\CodeGenerationFailedException.cs" />
<Compile Include="Compiler\CompilerGeneratedType.cs" />
diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs
index a57948b90..6070ec35d 100644
--- a/src/ILCompiler/src/Program.cs
+++ b/src/ILCompiler/src/Program.cs
@@ -382,6 +382,16 @@ namespace ILCompiler
else
builder = new RyuJitCompilationBuilder(typeSystemContext, compilationGroup);
+ var stackTracePolicy = _emitStackTraceData ?
+ (StackTraceEmissionPolicy)new EcmaMethodStackTraceEmissionPolicy() : new NoStackTraceEmissionPolicy();
+
+ UsageBasedMetadataManager metadataManager = new UsageBasedMetadataManager(
+ compilationGroup,
+ typeSystemContext,
+ new BlockedInternalsBlockingPolicy(),
+ _metadataLogFileName,
+ stackTracePolicy);
+
// Unless explicitly opted in at the command line, we enable scanner for retail builds by default.
// We don't do this for CppCodegen and Wasm, because those codegens are behind.
// We also don't do this for multifile because scanner doesn't simulate inlining (this would be
@@ -392,11 +402,13 @@ namespace ILCompiler
useScanner &= !_noScanner;
+ MetadataManager compilationMetadataManager = _isWasmCodegen ? (MetadataManager)new EmptyMetadataManager(typeSystemContext) : metadataManager;
ILScanResults scanResults = null;
if (useScanner)
{
ILScannerBuilder scannerBuilder = builder.GetILScannerBuilder()
- .UseCompilationRoots(compilationRoots);
+ .UseCompilationRoots(compilationRoots)
+ .UseMetadataManager(metadataManager);
if (_scanDgmlLogFileName != null)
scannerBuilder.UseDependencyTracking(_generateFullScanDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
@@ -404,6 +416,8 @@ namespace ILCompiler
IILScanner scanner = scannerBuilder.ToILScanner();
scanResults = scanner.Scan();
+
+ compilationMetadataManager = metadataManager.ToAnalysisBasedMetadataManager();
}
var logger = new Logger(Console.Out, _isVerbose);
@@ -415,19 +429,11 @@ namespace ILCompiler
DependencyTrackingLevel trackingLevel = _dgmlLogFileName == null ?
DependencyTrackingLevel.None : (_generateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
- var stackTracePolicy = _emitStackTraceData ?
- (StackTraceEmissionPolicy)new EcmaMethodStackTraceEmissionPolicy() : new NoStackTraceEmissionPolicy();
-
- UsageBasedMetadataManager metadataManager = new UsageBasedMetadataManager(
- compilationGroup,
- typeSystemContext,
- new BlockedInternalsBlockingPolicy(),
- _metadataLogFileName,
- stackTracePolicy);
+ compilationRoots.Add(compilationMetadataManager);
builder
.UseBackendOptions(_codegenOptions)
- .UseMetadataManager(metadataManager)
+ .UseMetadataManager(compilationMetadataManager)
.UseLogger(logger)
.UseDependencyTracking(trackingLevel)
.UseCompilationRoots(compilationRoots)