diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/AnalysisBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/AnalysisBasedMetadataManager.cs
index b748cc2c46c02d..8c24c7addbb080 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/AnalysisBasedMetadataManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/AnalysisBasedMetadataManager.cs
@@ -19,7 +19,7 @@ namespace ILCompiler
///
/// A metadata manager that knows the full set of metadata ahead of time.
///
- public sealed class AnalysisBasedMetadataManager : GeneratingMetadataManager, ICompilationRootProvider
+ public sealed class AnalysisBasedMetadataManager : MetadataManager, ICompilationRootProvider
{
private readonly List _modulesWithMetadata;
private readonly List _typesWithRootedCctorContext;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/GeneratingMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/GeneratingMetadataManager.cs
deleted file mode 100644
index 1e7442fec74862..00000000000000
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/GeneratingMetadataManager.cs
+++ /dev/null
@@ -1,224 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-using System.Text;
-using Internal.TypeSystem;
-using Internal.Metadata.NativeFormat.Writer;
-
-using ILCompiler.Metadata;
-using ILCompiler.DependencyAnalysis;
-
-using Debug = System.Diagnostics.Debug;
-
-namespace ILCompiler
-{
- ///
- /// Base class for metadata managers that generate metadata blobs.
- ///
- public abstract class GeneratingMetadataManager : MetadataManager
- {
- protected readonly string _metadataLogFile;
- protected readonly StackTraceEmissionPolicy _stackTraceEmissionPolicy;
- private readonly ModuleDesc _generatedAssembly;
-
- public GeneratingMetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy,
- ManifestResourceBlockingPolicy resourceBlockingPolicy, string logFile, StackTraceEmissionPolicy stackTracePolicy,
- DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy, MetadataManagerOptions options)
- : base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, invokeThunkGenerationPolicy, options)
- {
- _metadataLogFile = logFile;
- _stackTraceEmissionPolicy = stackTracePolicy;
- _generatedAssembly = typeSystemContext.GeneratedAssembly;
- }
-
- public sealed override bool WillUseMetadataTokenToReferenceMethod(MethodDesc method)
- {
- return (GetMetadataCategory(method) & MetadataCategory.Description) != 0;
- }
-
- public sealed override bool WillUseMetadataTokenToReferenceField(FieldDesc field)
- {
- return (GetMetadataCategory(field) & MetadataCategory.Description) != 0;
- }
-
- protected void ComputeMetadata(
- TPolicy policy,
- NodeFactory factory,
- out byte[] metadataBlob,
- out List> typeMappings,
- out List> methodMappings,
- out List> fieldMappings,
- out List stackTraceMapping) where TPolicy : struct, IMetadataPolicy
- {
- var transformed = MetadataTransform.Run(policy, GetCompilationModulesWithMetadata());
- MetadataTransform transform = transformed.Transform;
-
- // Generate metadata blob
- var writer = new MetadataWriter();
- writer.ScopeDefinitions.AddRange(transformed.Scopes);
-
- // Generate entries in the blob for methods that will be necessary for stack trace purposes.
- var stackTraceRecords = new List();
- foreach (var methodBody in GetCompiledMethodBodies())
- {
- MethodDesc method = methodBody.Method;
-
- MethodDesc typicalMethod = method.GetTypicalMethodDefinition();
-
- // 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) &&
- (GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) != 0)
- continue;
-
- MethodStackTraceVisibilityFlags stackVisibility = _stackTraceEmissionPolicy.GetMethodVisibility(method);
- bool isHidden = (stackVisibility & MethodStackTraceVisibilityFlags.IsHidden) != 0;
-
- if ((stackVisibility & MethodStackTraceVisibilityFlags.HasMetadata) != 0)
- {
- StackTraceRecordData record = CreateStackTraceRecord(transform, method, isHidden);
-
- stackTraceRecords.Add(record);
-
- writer.AdditionalRootRecords.Add(record.OwningType);
- writer.AdditionalRootRecords.Add(record.MethodName);
- writer.AdditionalRootRecords.Add(record.MethodSignature);
- writer.AdditionalRootRecords.Add(record.MethodInstantiationArgumentCollection);
- }
- else if (isHidden)
- {
- stackTraceRecords.Add(new StackTraceRecordData(method, null, null, null, null, isHidden));
- }
- }
-
- var ms = new MemoryStream();
-
- // .NET metadata is UTF-16 and UTF-16 contains code points that don't translate to UTF-8.
- var noThrowUtf8Encoding = new UTF8Encoding(false, false);
-
- using (var logWriter = _metadataLogFile != null ? new StreamWriter(File.Open(_metadataLogFile, FileMode.Create, FileAccess.Write, FileShare.Read), noThrowUtf8Encoding) : null)
- {
- writer.LogWriter = logWriter;
- writer.Write(ms);
- }
-
- metadataBlob = ms.ToArray();
-
- const int MaxAllowedMetadataOffset = 0xFFFFFF;
- if (metadataBlob.Length > MaxAllowedMetadataOffset)
- {
- // Offset portion of metadata handles is limited to 16 MB.
- throw new InvalidOperationException($"Metadata blob exceeded the addressing range (allowed: {MaxAllowedMetadataOffset}, actual: {metadataBlob.Length})");
- }
-
- typeMappings = new List>();
- methodMappings = new List>();
- fieldMappings = new List>();
- stackTraceMapping = new List();
-
- // Generate type definition mappings
- foreach (var type in factory.MetadataManager.GetTypesWithEETypes())
- {
- MetadataType definition = type.IsTypeDefinition ? type as MetadataType : null;
- if (definition == null)
- continue;
-
- MetadataRecord record = transformed.GetTransformedTypeDefinition(definition);
-
- // Reflection requires that we maintain type identity. Even if we only generated a TypeReference record,
- // if there is an MethodTable for it, we also need a mapping table entry for it.
- record ??= transformed.GetTransformedTypeReference(definition);
-
- if (record != null)
- typeMappings.Add(new MetadataMapping(definition, writer.GetRecordHandle(record)));
- }
-
- foreach (var method in GetReflectableMethods())
- {
- if (method.IsGenericMethodDefinition || method.OwningType.IsGenericDefinition)
- {
- // Generic definitions don't have runtime artifacts we would need to map to.
- continue;
- }
-
- if (method.GetCanonMethodTarget(CanonicalFormKind.Specific) != method)
- {
- // Methods that are not in their canonical form are not interesting
- continue;
- }
-
- 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)
- methodMappings.Add(new MetadataMapping(method, writer.GetRecordHandle(record)));
- }
-
- HashSet canonicalFields = new HashSet();
- foreach (var field in GetFieldsWithRuntimeMapping())
- {
- FieldDesc fieldToAdd = field;
- TypeDesc canonOwningType = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
- if (canonOwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
- {
- FieldDesc canonField = _typeSystemContext.GetFieldForInstantiatedType(field.GetTypicalFieldDefinition(), (InstantiatedType)canonOwningType);
-
- // If we already added a canonically equivalent field, skip this one.
- if (!canonicalFields.Add(canonField))
- continue;
-
- fieldToAdd = canonField;
- }
-
- Field record = transformed.GetTransformedFieldDefinition(fieldToAdd.GetTypicalFieldDefinition());
- if (record != null)
- fieldMappings.Add(new MetadataMapping(fieldToAdd, writer.GetRecordHandle(record)));
- }
-
- // Generate stack trace metadata mapping
- foreach (var stackTraceRecord in stackTraceRecords)
- {
- if (stackTraceRecord.OwningType != null)
- {
- StackTraceMapping mapping = new StackTraceMapping(
- stackTraceRecord.Method,
- writer.GetRecordHandle(stackTraceRecord.OwningType),
- writer.GetRecordHandle(stackTraceRecord.MethodSignature),
- writer.GetRecordHandle(stackTraceRecord.MethodName),
- stackTraceRecord.MethodInstantiationArgumentCollection != null ? writer.GetRecordHandle(stackTraceRecord.MethodInstantiationArgumentCollection) : 0,
- stackTraceRecord.IsHidden);
- stackTraceMapping.Add(mapping);
- }
- else
- {
- Debug.Assert(stackTraceRecord.IsHidden);
- stackTraceMapping.Add(new StackTraceMapping(stackTraceRecord.Method, 0, 0, 0, 0, stackTraceRecord.IsHidden));
- }
- }
- }
-
- ///
- /// Gets a list of fields that got "compiled" and are eligible for a runtime mapping.
- ///
- ///
- protected abstract IEnumerable GetFieldsWithRuntimeMapping();
-
- ///
- /// Gets a stub that can be used to reflection-invoke a method with a given signature.
- ///
- public sealed override MethodDesc GetReflectionInvokeStub(MethodDesc method)
- {
- return _typeSystemContext.GetDynamicInvokeThunk(method.Signature,
- !method.Signature.IsStatic && method.OwningType.IsValueType);
- }
- }
-}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
index 5058524c8cecb4..2f92ccdb9048e7 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
@@ -3,11 +3,14 @@
using System;
using System.Collections.Generic;
+using System.IO;
+using System.Text;
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
+using ILCompiler.Metadata;
using Debug = System.Diagnostics.Debug;
using ReadyToRunSectionType = Internal.Runtime.ReadyToRunSectionType;
@@ -17,9 +20,12 @@
using CombinedDependencyListEntry = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore.CombinedDependencyListEntry;
using MethodIL = Internal.IL.MethodIL;
using CustomAttributeValue = System.Reflection.Metadata.CustomAttributeValue;
+using MethodSignature = Internal.TypeSystem.MethodSignature;
using MetadataRecord = Internal.Metadata.NativeFormat.Writer.MetadataRecord;
+using MetadataWriter = Internal.Metadata.NativeFormat.Writer.MetadataWriter;
using TypeReference = Internal.Metadata.NativeFormat.Writer.TypeReference;
+using Field = Internal.Metadata.NativeFormat.Writer.Field;
using TypeSpecification = Internal.Metadata.NativeFormat.Writer.TypeSpecification;
using ConstantStringValue = Internal.Metadata.NativeFormat.Writer.ConstantStringValue;
using TypeInstantiationSignature = Internal.Metadata.NativeFormat.Writer.TypeInstantiationSignature;
@@ -43,6 +49,8 @@ public abstract class MetadataManager : ICompilationRootProvider
private List> _fieldMappings;
private List> _methodMappings;
private List _stackTraceMappings;
+ protected readonly string _metadataLogFile;
+ protected readonly StackTraceEmissionPolicy _stackTraceEmissionPolicy;
protected readonly CompilerTypeSystemContext _typeSystemContext;
protected readonly MetadataBlockingPolicy _blockingPolicy;
@@ -75,7 +83,8 @@ private readonly SortedSet _typeGVMEntries
internal NativeLayoutInfoNode NativeLayoutInfo { get; private set; }
public MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy,
- ManifestResourceBlockingPolicy resourceBlockingPolicy, DynamicInvokeThunkGenerationPolicy dynamicInvokeThunkGenerationPolicy,
+ ManifestResourceBlockingPolicy resourceBlockingPolicy, string logFile, StackTraceEmissionPolicy stackTracePolicy,
+ DynamicInvokeThunkGenerationPolicy dynamicInvokeThunkGenerationPolicy,
MetadataManagerOptions options)
{
_typeSystemContext = typeSystemContext;
@@ -83,6 +92,8 @@ public MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBloc
_resourceBlockingPolicy = resourceBlockingPolicy;
_dynamicInvokeThunkGenerationPolicy = dynamicInvokeThunkGenerationPolicy;
_options = options;
+ _metadataLogFile = logFile;
+ _stackTraceEmissionPolicy = stackTracePolicy;
}
public bool IsDataDehydrated => (_options & MetadataManagerOptions.DehydrateData) != 0;
@@ -561,6 +572,12 @@ public virtual void GetDependenciesForOverridingMethod(ref CombinedDependencyLis
{
}
+ ///
+ /// Gets a list of fields that got "compiled" and are eligible for a runtime mapping.
+ ///
+ ///
+ protected abstract IEnumerable GetFieldsWithRuntimeMapping();
+
///
/// This method is an extension point that can provide additional metadata-based dependencies to generated method bodies.
///
@@ -601,18 +618,28 @@ public bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method)
/// Given that a method is invokable, if it is inserted into the reflection invoke table
/// will it use a method token to be referenced, or not?
///
- public abstract bool WillUseMetadataTokenToReferenceMethod(MethodDesc method);
+ public bool WillUseMetadataTokenToReferenceMethod(MethodDesc method)
+ {
+ return (GetMetadataCategory(method) & MetadataCategory.Description) != 0;
+ }
///
/// Given that a method is invokable, if it is inserted into the reflection invoke table
/// will it use a field token to be referenced, or not?
///
- public abstract bool WillUseMetadataTokenToReferenceField(FieldDesc field);
+ public bool WillUseMetadataTokenToReferenceField(FieldDesc field)
+ {
+ return (GetMetadataCategory(field) & MetadataCategory.Description) != 0;
+ }
///
/// Gets a stub that can be used to reflection-invoke a method with a given signature.
///
- public abstract MethodDesc GetReflectionInvokeStub(MethodDesc method);
+ public MethodDesc GetReflectionInvokeStub(MethodDesc method)
+ {
+ return _typeSystemContext.GetDynamicInvokeThunk(method.Signature,
+ !method.Signature.IsStatic && method.OwningType.IsValueType);
+ }
protected void EnsureMetadataGenerated(NodeFactory factory)
{
@@ -635,6 +662,168 @@ protected abstract void ComputeMetadata(NodeFactory factory,
out List> fieldMappings,
out List stackTraceMapping);
+ protected void ComputeMetadata(
+ TPolicy policy,
+ NodeFactory factory,
+ out byte[] metadataBlob,
+ out List> typeMappings,
+ out List> methodMappings,
+ out List> fieldMappings,
+ out List stackTraceMapping) where TPolicy : struct, IMetadataPolicy
+ {
+ var transformed = MetadataTransform.Run(policy, GetCompilationModulesWithMetadata());
+ MetadataTransform transform = transformed.Transform;
+
+ // Generate metadata blob
+ var writer = new MetadataWriter();
+ writer.ScopeDefinitions.AddRange(transformed.Scopes);
+
+ // Generate entries in the blob for methods that will be necessary for stack trace purposes.
+ var stackTraceRecords = new List();
+ foreach (var methodBody in GetCompiledMethodBodies())
+ {
+ MethodDesc method = methodBody.Method;
+
+ MethodDesc typicalMethod = method.GetTypicalMethodDefinition();
+
+ // 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) &&
+ (GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) != 0)
+ continue;
+
+ MethodStackTraceVisibilityFlags stackVisibility = _stackTraceEmissionPolicy.GetMethodVisibility(method);
+ bool isHidden = (stackVisibility & MethodStackTraceVisibilityFlags.IsHidden) != 0;
+
+ if ((stackVisibility & MethodStackTraceVisibilityFlags.HasMetadata) != 0)
+ {
+ StackTraceRecordData record = CreateStackTraceRecord(transform, method, isHidden);
+
+ stackTraceRecords.Add(record);
+
+ writer.AdditionalRootRecords.Add(record.OwningType);
+ writer.AdditionalRootRecords.Add(record.MethodName);
+ writer.AdditionalRootRecords.Add(record.MethodSignature);
+ writer.AdditionalRootRecords.Add(record.MethodInstantiationArgumentCollection);
+ }
+ else if (isHidden)
+ {
+ stackTraceRecords.Add(new StackTraceRecordData(method, null, null, null, null, isHidden));
+ }
+ }
+
+ var ms = new MemoryStream();
+
+ // .NET metadata is UTF-16 and UTF-16 contains code points that don't translate to UTF-8.
+ var noThrowUtf8Encoding = new UTF8Encoding(false, false);
+
+ using (var logWriter = _metadataLogFile != null ? new StreamWriter(File.Open(_metadataLogFile, FileMode.Create, FileAccess.Write, FileShare.Read), noThrowUtf8Encoding) : null)
+ {
+ writer.LogWriter = logWriter;
+ writer.Write(ms);
+ }
+
+ metadataBlob = ms.ToArray();
+
+ const int MaxAllowedMetadataOffset = 0xFFFFFF;
+ if (metadataBlob.Length > MaxAllowedMetadataOffset)
+ {
+ // Offset portion of metadata handles is limited to 16 MB.
+ throw new InvalidOperationException($"Metadata blob exceeded the addressing range (allowed: {MaxAllowedMetadataOffset}, actual: {metadataBlob.Length})");
+ }
+
+ typeMappings = new List>();
+ methodMappings = new List>();
+ fieldMappings = new List>();
+ stackTraceMapping = new List();
+
+ // Generate type definition mappings
+ foreach (var type in factory.MetadataManager.GetTypesWithEETypes())
+ {
+ MetadataType definition = type.IsTypeDefinition ? type as MetadataType : null;
+ if (definition == null)
+ continue;
+
+ MetadataRecord record = transformed.GetTransformedTypeDefinition(definition);
+
+ // Reflection requires that we maintain type identity. Even if we only generated a TypeReference record,
+ // if there is an MethodTable for it, we also need a mapping table entry for it.
+ record ??= transformed.GetTransformedTypeReference(definition);
+
+ if (record != null)
+ typeMappings.Add(new MetadataMapping(definition, writer.GetRecordHandle(record)));
+ }
+
+ foreach (var method in GetReflectableMethods())
+ {
+ if (method.IsGenericMethodDefinition || method.OwningType.IsGenericDefinition)
+ {
+ // Generic definitions don't have runtime artifacts we would need to map to.
+ continue;
+ }
+
+ if (method.GetCanonMethodTarget(CanonicalFormKind.Specific) != method)
+ {
+ // Methods that are not in their canonical form are not interesting
+ continue;
+ }
+
+ 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)
+ methodMappings.Add(new MetadataMapping(method, writer.GetRecordHandle(record)));
+ }
+
+ HashSet canonicalFields = new HashSet();
+ foreach (var field in GetFieldsWithRuntimeMapping())
+ {
+ FieldDesc fieldToAdd = field;
+ TypeDesc canonOwningType = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
+ if (canonOwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
+ {
+ FieldDesc canonField = _typeSystemContext.GetFieldForInstantiatedType(field.GetTypicalFieldDefinition(), (InstantiatedType)canonOwningType);
+
+ // If we already added a canonically equivalent field, skip this one.
+ if (!canonicalFields.Add(canonField))
+ continue;
+
+ fieldToAdd = canonField;
+ }
+
+ Field record = transformed.GetTransformedFieldDefinition(fieldToAdd.GetTypicalFieldDefinition());
+ if (record != null)
+ fieldMappings.Add(new MetadataMapping(fieldToAdd, writer.GetRecordHandle(record)));
+ }
+
+ // Generate stack trace metadata mapping
+ foreach (var stackTraceRecord in stackTraceRecords)
+ {
+ if (stackTraceRecord.OwningType != null)
+ {
+ StackTraceMapping mapping = new StackTraceMapping(
+ stackTraceRecord.Method,
+ writer.GetRecordHandle(stackTraceRecord.OwningType),
+ writer.GetRecordHandle(stackTraceRecord.MethodSignature),
+ writer.GetRecordHandle(stackTraceRecord.MethodName),
+ stackTraceRecord.MethodInstantiationArgumentCollection != null ? writer.GetRecordHandle(stackTraceRecord.MethodInstantiationArgumentCollection) : 0,
+ stackTraceRecord.IsHidden);
+ stackTraceMapping.Add(mapping);
+ }
+ else
+ {
+ Debug.Assert(stackTraceRecord.IsHidden);
+ stackTraceMapping.Add(new StackTraceMapping(stackTraceRecord.Method, 0, 0, 0, 0, stackTraceRecord.IsHidden));
+ }
+ }
+ }
+
protected StackTraceRecordData CreateStackTraceRecord(Metadata.MetadataTransform transform, MethodDesc method, bool isHidden)
{
// In the metadata, we only represent the generic definition
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
index 1f798698ba1514..2b823f42465108 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
@@ -34,7 +34,7 @@ namespace ILCompiler
/// This class is responsible for managing native metadata to be emitted into the compiled
/// module. It applies a policy that every type/method that is statically used shall be reflectable.
///
- public sealed class UsageBasedMetadataManager : GeneratingMetadataManager
+ public sealed class UsageBasedMetadataManager : MetadataManager
{
private readonly CompilationModuleGroup _compilationModuleGroup;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
index 1137962a793221..6a35c1cc5c9063 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
@@ -455,7 +455,6 @@
-