diff options
author | Michal Strehovský <michals@microsoft.com> | 2017-12-17 17:55:09 +0300 |
---|---|---|
committer | Michal Strehovský <michals@microsoft.com> | 2017-12-18 14:29:13 +0300 |
commit | ea415ea2ce856e50c5ca61c52e8153af48c2e928 (patch) | |
tree | edf33d40970a44a3fbe886a91f57f32dfbee0f89 | |
parent | 243c3ef555f525550317f834dd4a8aac8ccfcb66 (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.
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) |