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ý <MichalStrehovsky@users.noreply.github.com>2017-05-23 04:31:42 +0300
committerGitHub <noreply@github.com>2017-05-23 04:31:42 +0300
commitdfcefa77c07a33938370f216d96e9b20066766de (patch)
tree621188f3e729c0a9f631ec789a94c46dded699ad
parent0df43f3f22e5f52bf0f92bd54ab19d2455bcbc84 (diff)
parent7867539d3123f3312a8100f2f1063c69ac2aae55 (diff)
Merge pull request #3664 from MichalStrehovsky/mdManagerCreation
Make metadata generation dependency driven
-rw-r--r--src/Common/src/TypeSystem/Common/FieldDesc.cs8
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs20
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/CompilerGeneratedMetadataManager.cs174
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs204
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodMetadataNode.cs61
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ModuleMetadataNode.cs59
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs36
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataNode.cs114
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs29
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/MetadataBlockingPolicy.cs62
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs155
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs31
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs4
-rw-r--r--src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj5
-rw-r--r--src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs3
-rw-r--r--src/ILCompiler/src/Program.cs4
16 files changed, 823 insertions, 146 deletions
diff --git a/src/Common/src/TypeSystem/Common/FieldDesc.cs b/src/Common/src/TypeSystem/Common/FieldDesc.cs
index cfdc3d12d..be2d81bd5 100644
--- a/src/Common/src/TypeSystem/Common/FieldDesc.cs
+++ b/src/Common/src/TypeSystem/Common/FieldDesc.cs
@@ -76,6 +76,14 @@ namespace Internal.TypeSystem
return this;
}
+ public bool IsTypicalFieldDefinition
+ {
+ get
+ {
+ return GetTypicalFieldDefinition() == this;
+ }
+ }
+
public virtual FieldDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation)
{
FieldDesc field = this;
diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs b/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs
index 698d7a46f..838606a9d 100644
--- a/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs
@@ -23,13 +23,14 @@ namespace ILCompiler
protected IEnumerable<ICompilationRootProvider> _compilationRoots = Array.Empty<ICompilationRootProvider>();
protected OptimizationMode _optimizationMode = OptimizationMode.None;
protected bool _generateDebugInfo = false;
- private string _metadataLogFile = null;
+ protected MetadataManager _metadataManager;
public CompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup compilationGroup, NameMangler nameMangler)
{
_context = context;
_compilationGroup = compilationGroup;
_nameMangler = nameMangler;
+ _metadataManager = new EmptyMetadataManager(compilationGroup, context);
}
public CompilationBuilder UseLogger(Logger logger)
@@ -44,21 +45,21 @@ namespace ILCompiler
return this;
}
- public CompilationBuilder UseCompilationRoots(IEnumerable<ICompilationRootProvider> compilationRoots)
+ public CompilationBuilder UseMetadataManager(MetadataManager metadataManager)
{
- _compilationRoots = compilationRoots;
+ _metadataManager = metadataManager;
return this;
}
- public CompilationBuilder UseOptimizationMode(OptimizationMode mode)
+ public CompilationBuilder UseCompilationRoots(IEnumerable<ICompilationRootProvider> compilationRoots)
{
- _optimizationMode = mode;
+ _compilationRoots = compilationRoots;
return this;
}
- public CompilationBuilder UseMetadataLogFile(string fileName)
+ public CompilationBuilder UseOptimizationMode(OptimizationMode mode)
{
- _metadataLogFile = fileName;
+ _optimizationMode = mode;
return this;
}
@@ -76,11 +77,6 @@ namespace ILCompiler
return _dependencyTrackingLevel.CreateDependencyGraph(factory);
}
- protected MetadataManager CreateMetadataManager()
- {
- return new CompilerGeneratedMetadataManager(_compilationGroup, _context, _metadataLogFile);
- }
-
public ILScannerBuilder GetILScannerBuilder(CompilationModuleGroup compilationGroup = null)
{
return new ILScannerBuilder(_context, compilationGroup ?? _compilationGroup, _nameMangler);
diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilerGeneratedMetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/CompilerGeneratedMetadataManager.cs
index 3e1a5c368..9026446e2 100644
--- a/src/ILCompiler.Compiler/src/Compiler/CompilerGeneratedMetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/CompilerGeneratedMetadataManager.cs
@@ -15,6 +15,7 @@ using ILCompiler.Metadata;
using ILCompiler.DependencyAnalysis;
using Debug = System.Diagnostics.Debug;
+using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
namespace ILCompiler
{
@@ -22,56 +23,70 @@ 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 emitted shall be reflectable.
/// </summary>
- public class CompilerGeneratedMetadataManager : MetadataManager
+ public sealed class CompilerGeneratedMetadataManager : MetadataManager
{
- private GeneratedTypesAndCodeMetadataPolicy _metadataPolicy;
- private string _metadataLogFile;
+ private readonly string _metadataLogFile;
+ private Dictionary<DynamicInvokeMethodSignature, MethodDesc> _dynamicInvokeThunks = new Dictionary<DynamicInvokeMethodSignature, MethodDesc>();
public CompilerGeneratedMetadataManager(CompilationModuleGroup group, CompilerTypeSystemContext typeSystemContext, string logFile)
- : base(group, typeSystemContext)
+ : base(group, typeSystemContext, new BlockedInternalsBlockingPolicy())
{
- _metadataPolicy = new GeneratedTypesAndCodeMetadataPolicy(this);
_metadataLogFile = logFile;
}
- private HashSet<MetadataType> _typeDefinitionsToGenerate = new HashSet<MetadataType>();
- private HashSet<MethodDesc> _methodDefinitionsToGenerate = new HashSet<MethodDesc>();
- private HashSet<ModuleDesc> _modulesSeen = new HashSet<ModuleDesc>();
- private Dictionary<DynamicInvokeMethodSignature, MethodDesc> _dynamicInvokeThunks = new Dictionary<DynamicInvokeMethodSignature, MethodDesc>();
-
- public override IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata()
- {
- return _modulesSeen;
- }
-
- public override bool IsReflectionBlocked(MetadataType type)
- {
- return _metadataPolicy.IsBlocked(type);
- }
-
public override bool WillUseMetadataTokenToReferenceMethod(MethodDesc method)
{
- return _compilationModuleGroup.ContainsType(method.GetTypicalMethodDefinition().OwningType);
+ return (GetMetadataCategory(method) & MetadataCategory.Description) != 0;
}
public override bool WillUseMetadataTokenToReferenceField(FieldDesc field)
{
- return _compilationModuleGroup.ContainsType(field.GetTypicalFieldDefinition().OwningType);
+ return (GetMetadataCategory(field) & MetadataCategory.Description) != 0;
}
protected override MetadataCategory GetMetadataCategory(FieldDesc field)
{
- return MetadataCategory.RuntimeMapping;
+ MetadataCategory category = 0;
+
+ if (!IsReflectionBlocked(field))
+ {
+ category = MetadataCategory.RuntimeMapping;
+
+ if (_compilationModuleGroup.ContainsType(field.GetTypicalFieldDefinition().OwningType))
+ category |= MetadataCategory.Description;
+ }
+
+ return category;
}
protected override MetadataCategory GetMetadataCategory(MethodDesc method)
{
- return MetadataCategory.RuntimeMapping;
+ MetadataCategory category = 0;
+
+ if (!IsReflectionBlocked(method))
+ {
+ category = MetadataCategory.RuntimeMapping;
+
+ if (_compilationModuleGroup.ContainsType(method.GetTypicalMethodDefinition().OwningType))
+ category |= MetadataCategory.Description;
+ }
+
+ return category;
}
protected override MetadataCategory GetMetadataCategory(TypeDesc type)
{
- return MetadataCategory.RuntimeMapping;
+ MetadataCategory category = 0;
+
+ if (!IsReflectionBlocked(type))
+ {
+ category = MetadataCategory.RuntimeMapping;
+
+ if (_compilationModuleGroup.ContainsType(type.GetTypeDefinition()))
+ category |= MetadataCategory.Description;
+ }
+
+ return category;
}
protected override void ComputeMetadata(NodeFactory factory,
@@ -80,34 +95,7 @@ namespace ILCompiler
out List<MetadataMapping<MethodDesc>> methodMappings,
out List<MetadataMapping<FieldDesc>> fieldMappings)
{
- foreach (var type in factory.MetadataManager.GetTypesWithEETypes())
- {
- var definition = type.GetTypeDefinition() as Internal.TypeSystem.Ecma.EcmaType;
- if (definition == null)
- continue;
- if (factory.CompilationModuleGroup.ContainsType(definition))
- {
- _typeDefinitionsToGenerate.Add(definition);
- _modulesSeen.Add(definition.Module);
- }
- }
-
- foreach (var method in GetCompiledMethods())
- {
- var typicalMethod = method.GetTypicalMethodDefinition() as Internal.TypeSystem.Ecma.EcmaMethod;
- if (typicalMethod != null)
- {
- var owningType = (MetadataType)typicalMethod.OwningType;
- if (factory.CompilationModuleGroup.ContainsType(owningType))
- {
- _typeDefinitionsToGenerate.Add(owningType);
- _modulesSeen.Add(owningType.Module);
- _methodDefinitionsToGenerate.Add(typicalMethod);
- }
- }
- }
-
- var transformed = MetadataTransform.Run(new GeneratedTypesAndCodeMetadataPolicy(this), _modulesSeen);
+ var transformed = MetadataTransform.Run(new GeneratedTypesAndCodeMetadataPolicy(this, factory), GetCompilationModulesWithMetadata());
// TODO: DeveloperExperienceMode: Use transformed.Transform.HandleType() to generate
// TypeReference records for _typeDefinitionsGenerated that don't have metadata.
@@ -194,7 +182,14 @@ namespace ILCompiler
public override bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method)
{
Debug.Assert(IsReflectionInvokable(method));
- return true;
+
+ // Place an upper limit on how many parameters a method can have to still get a static stub.
+ // From the past experience, methods taking 8000+ parameters get a stub that can hit various limitations
+ // in the codegen. On Project N, we were limited to 256 parameters because of MDIL limitations.
+ // We don't have such limitations here, but it's a nice round number.
+ // Reflection invoke will still work, but will go through the calling convention converter.
+
+ return method.Signature.Length <= 256;
}
/// <summary>
@@ -217,79 +212,48 @@ namespace ILCompiler
return InstantiateCanonicalDynamicInvokeMethodForMethod(thunk, method);
}
+ protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
+ {
+ dependencies = dependencies ?? new DependencyList();
+ dependencies.Add(factory.MethodMetadata(method.GetTypicalMethodDefinition()), "Reflectable method");
+ }
+
+ protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
+ {
+ TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, type, "Reflectable type");
+ }
+
private struct GeneratedTypesAndCodeMetadataPolicy : IMetadataPolicy
{
- private CompilerGeneratedMetadataManager _parent;
- private ExplicitScopeAssemblyPolicyMixin _explicitScopeMixin;
- private Dictionary<MetadataType, bool> _isAttributeCache;
+ private readonly CompilerGeneratedMetadataManager _parent;
+ private readonly NodeFactory _factory;
+ private readonly ExplicitScopeAssemblyPolicyMixin _explicitScopeMixin;
- public GeneratedTypesAndCodeMetadataPolicy(CompilerGeneratedMetadataManager parent)
+ public GeneratedTypesAndCodeMetadataPolicy(CompilerGeneratedMetadataManager parent, NodeFactory factory)
{
_parent = parent;
+ _factory = factory;
_explicitScopeMixin = new ExplicitScopeAssemblyPolicyMixin();
-
- MetadataType systemAttributeType = parent._typeSystemContext.SystemModule.GetType("System", "Attribute", false);
- _isAttributeCache = new Dictionary<MetadataType, bool>();
- _isAttributeCache.Add(systemAttributeType, true);
}
public bool GeneratesMetadata(FieldDesc fieldDef)
{
- return _parent._typeDefinitionsToGenerate.Contains((MetadataType)fieldDef.OwningType);
+ return _factory.TypeMetadata((MetadataType)fieldDef.OwningType).Marked;
}
public bool GeneratesMetadata(MethodDesc methodDef)
{
- return _parent._methodDefinitionsToGenerate.Contains(methodDef);
+ return _factory.MethodMetadata(methodDef).Marked;
}
public bool GeneratesMetadata(MetadataType typeDef)
{
- // Global module type always generates metadata. This is e.g. used in various places
- // where we need a metadata enabled type from an assembly but we don't have a convenient way
- // to find one.
- // We don't need to worry about metadata consistency (accidentally generating metadata
- // that can't be used with any reflection API at runtime because it's incomplete) because
- // global module types don't derive from anything and have an empty interface list.
- if (typeDef.IsModuleType)
- return true;
-
- // Metadata consistency: if a nested type generates metadata, the containing type is
- // required to generate metadata, or metadata generation will fail.
- foreach (var nested in typeDef.GetNestedTypes())
- {
- if (GeneratesMetadata(nested))
- return true;
- }
-
- return _parent._typeDefinitionsToGenerate.Contains(typeDef);
+ return _factory.TypeMetadata(typeDef).Marked;
}
public bool IsBlocked(MetadataType typeDef)
{
- // If an attribute type would generate metadata in this blob (had we compiled it), consider it blocked.
- // Otherwise we end up with an attribute that is an unresolvable TypeRef and we would get a TypeLoadException
- // when enumerating attributes on anything that has it.
- if (!GeneratesMetadata(typeDef)
- && _parent._compilationModuleGroup.ContainsType(typeDef)
- && IsAttributeType(typeDef))
- {
- return true;
- }
-
- return false;
- }
-
- private bool IsAttributeType(MetadataType type)
- {
- bool result;
- if (!_isAttributeCache.TryGetValue(type, out result))
- {
- MetadataType baseType = type.MetadataBaseType;
- result = baseType != null && IsAttributeType(baseType);
- _isAttributeCache.Add(type, result);
- }
- return result;
+ return _parent._blockingPolicy.IsBlocked(typeDef);
}
public ModuleDesc GetModuleOfType(MetadataType typeDef)
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs
new file mode 100644
index 000000000..28cee9b04
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs
@@ -0,0 +1,204 @@
+// 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.Immutable;
+using System.Diagnostics;
+using System.Reflection.Metadata;
+
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ /// <summary>
+ /// Computes the list of dependencies that are necessary to generate metadata for a custom attribute, but also the dependencies to
+ /// make the custom attributes usable by the reflection stack at runtime.
+ /// </summary>
+ internal class CustomAttributeBasedDependencyAlgorithm
+ {
+ public static void AddDependenciesDueToCustomAttributes(ref DependencyList dependencies, NodeFactory factory, EcmaMethod method)
+ {
+ MetadataReader reader = method.MetadataReader;
+ MethodDefinition methodDef = reader.GetMethodDefinition(method.Handle);
+ AddDependenciesDueToCustomAttributes(ref dependencies, factory, method.Module, methodDef.GetCustomAttributes());
+ }
+
+ public static void AddDependenciesDueToCustomAttributes(ref DependencyList dependencies, NodeFactory factory, EcmaType type)
+ {
+ TypeDefinition typeDef = type.MetadataReader.GetTypeDefinition(type.Handle);
+ AddDependenciesDueToCustomAttributes(ref dependencies, factory, type.EcmaModule, typeDef.GetCustomAttributes());
+ }
+
+ public static void AddDependenciesDueToCustomAttributes(ref DependencyList dependencies, NodeFactory factory, EcmaField field)
+ {
+ FieldDefinition fieldDef = field.MetadataReader.GetFieldDefinition(field.Handle);
+ AddDependenciesDueToCustomAttributes(ref dependencies, factory, field.Module, fieldDef.GetCustomAttributes());
+ }
+
+ public static void AddDependenciesDueToCustomAttributes(ref DependencyList dependencies, NodeFactory factory, EcmaAssembly assembly)
+ {
+ AssemblyDefinition asmDef = assembly.MetadataReader.GetAssemblyDefinition();
+ AddDependenciesDueToCustomAttributes(ref dependencies, factory, assembly, asmDef.GetCustomAttributes());
+ }
+
+ private static void AddDependenciesDueToCustomAttributes(ref DependencyList dependencies, NodeFactory factory, EcmaModule module, CustomAttributeHandleCollection attributeHandles)
+ {
+ MetadataReader reader = module.MetadataReader;
+ MetadataManager mdManager = factory.MetadataManager;
+ var attributeTypeProvider = new CustomAttributeTypeProvider(module);
+
+
+ foreach (CustomAttributeHandle caHandle in attributeHandles)
+ {
+ CustomAttribute attribute = reader.GetCustomAttribute(caHandle);
+
+ try
+ {
+ MethodDesc constructor = module.GetMethod(attribute.Constructor);
+ if (mdManager.IsReflectionBlocked(constructor))
+ continue;
+
+ // Make a new list in case we need to abort.
+ var caDependencies = new DependencyList();
+
+ caDependencies.Add(factory.CanonicalEntrypoint(constructor), "Attribute constructor");
+ caDependencies.Add(factory.ConstructedTypeSymbol(constructor.OwningType), "Attribute type");
+
+ CustomAttributeValue<TypeDesc> decodedValue = attribute.DecodeValue(attributeTypeProvider);
+
+ if (AddDependenciesFromCustomAttributeBlob(caDependencies, factory, constructor.OwningType, decodedValue))
+ {
+ dependencies = dependencies ?? new DependencyList();
+ dependencies.AddRange(caDependencies);
+ }
+ }
+ catch (TypeSystemException)
+ {
+ // We could end up seeing an exception here for a multitude of reasons:
+ // * Attribute ctor doesn't resolve
+ // * There's a typeof() that refers to something that can't be loaded
+ // * Attribute refers to a non-existing field
+ // * Etc.
+ //
+ // If we really wanted to, we could probably come up with a way to still make this
+ // work with the same failure modes at runtime as the CLR, but it might not be
+ // worth the hassle: the input was invalid. The most important thing is that we
+ // don't crash the compilation.
+ }
+ }
+ }
+
+ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, CustomAttributeValue<TypeDesc> value)
+ {
+ MetadataManager mdManager = factory.MetadataManager;
+
+ foreach (CustomAttributeTypedArgument<TypeDesc> decodedArgument in value.FixedArguments)
+ {
+ if (!AddDependenciesFromCustomAttributeArgument(dependencies, factory, decodedArgument.Type, decodedArgument.Value))
+ return false;
+ }
+
+ foreach (CustomAttributeNamedArgument<TypeDesc> decodedArgument in value.NamedArguments)
+ {
+ if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
+ {
+ // This is an instance field. We don't track them right now.
+ }
+ else
+ {
+ Debug.Assert(decodedArgument.Kind == CustomAttributeNamedArgumentKind.Property);
+
+ // Reflection will need to reflection-invoke the setter at runtime.
+ if (!AddDependenciesFromPropertySetter(dependencies, factory, attributeType, decodedArgument.Name))
+ return false;
+ }
+
+ if (!AddDependenciesFromCustomAttributeArgument(dependencies, factory, decodedArgument.Type, decodedArgument.Value))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
+ {
+ EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
+
+ MetadataReader reader = attributeTypeDefinition.MetadataReader;
+ var typeDefinition = reader.GetTypeDefinition(attributeTypeDefinition.Handle);
+
+ foreach (PropertyDefinitionHandle propDefHandle in typeDefinition.GetProperties())
+ {
+ PropertyDefinition propDef = reader.GetPropertyDefinition(propDefHandle);
+ if (reader.StringComparer.Equals(propDef.Name, propertyName))
+ {
+ PropertyAccessors accessors = propDef.GetAccessors();
+
+ if (!accessors.Setter.IsNil)
+ {
+ MethodDesc setterMethod = (MethodDesc)attributeTypeDefinition.EcmaModule.GetObject(accessors.Setter);
+ if (factory.MetadataManager.IsReflectionBlocked(setterMethod))
+ return false;
+
+ // Method on a generic attribute
+ if (attributeType != attributeTypeDefinition)
+ {
+ setterMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(setterMethod, (InstantiatedType)attributeType);
+ }
+
+ // TODO: what if the setter is virtual/abstract?
+ dependencies.Add(factory.CanonicalEntrypoint(setterMethod), "Custom attribute blob");
+ }
+
+ return true;
+ }
+ }
+
+ // Haven't found it in current type. Check the base type.
+ TypeDesc baseType = attributeType.BaseType;
+
+ if (baseType != null)
+ return AddDependenciesFromPropertySetter(dependencies, factory, baseType, propertyName);
+
+ // Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
+ return true;
+ }
+
+ private static bool AddDependenciesFromCustomAttributeArgument(DependencyList dependencies, NodeFactory factory, TypeDesc type, object value)
+ {
+ if (type.UnderlyingType.IsPrimitive || type.IsString || value == null)
+ return true;
+
+ if (type.IsSzArray)
+ {
+ TypeDesc elementType = ((ArrayType)type).ElementType;
+ if (elementType.UnderlyingType.IsPrimitive || elementType.IsString)
+ return true;
+
+ foreach (CustomAttributeTypedArgument<TypeDesc> arrayElement in (ImmutableArray<CustomAttributeTypedArgument<TypeDesc>>)value)
+ {
+ if (!AddDependenciesFromCustomAttributeArgument(dependencies, factory, arrayElement.Type, arrayElement.Value))
+ return false;
+ }
+
+ return true;
+ }
+
+ // typeof() should be the only remaining option.
+
+ Debug.Assert(value is TypeDesc);
+
+ TypeDesc typeofType = (TypeDesc)value;
+
+ if (factory.MetadataManager.IsReflectionBlocked(typeofType))
+ return false;
+
+ TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, typeofType, "Custom attribute blob");
+
+ return true;
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodMetadataNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodMetadataNode.cs
new file mode 100644
index 000000000..04dd37671
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodMetadataNode.cs
@@ -0,0 +1,61 @@
+// 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.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+using EcmaMethod = Internal.TypeSystem.Ecma.EcmaMethod;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ /// <summary>
+ /// Represents a method that has metadata generated in the current compilation.
+ /// </summary>
+ /// <remarks>
+ /// Only expected to be used during ILScanning when scanning for reflection.
+ /// </remarks>
+ internal class MethodMetadataNode : DependencyNodeCore<NodeFactory>
+ {
+ private readonly MethodDesc _method;
+
+ public MethodMetadataNode(MethodDesc method)
+ {
+ Debug.Assert(method.IsTypicalMethodDefinition);
+ _method = method;
+ }
+
+ public MethodDesc Method => _method;
+
+ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
+ {
+ DependencyList dependencies = new DependencyList();
+ dependencies.Add(factory.TypeMetadata((MetadataType)_method.OwningType), "Owning type metadata");
+
+ CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, ((EcmaMethod)_method));
+
+ return dependencies;
+ }
+ protected override string GetName(NodeFactory factory)
+ {
+ return "Reflectable method: " + _method.ToString();
+ }
+
+ protected override void OnMarked(NodeFactory factory)
+ {
+ Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_method));
+ Debug.Assert(factory.MetadataManager.CanGenerateMetadata(_method));
+ }
+
+ public override bool InterestingForDynamicDependencyAnalysis => false;
+ public override bool HasDynamicDependencies => false;
+ public override bool HasConditionalStaticDependencies => false;
+ public override bool StaticDependenciesAreComputed => true;
+ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
+ public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ModuleMetadataNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ModuleMetadataNode.cs
new file mode 100644
index 000000000..f152dc988
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ModuleMetadataNode.cs
@@ -0,0 +1,59 @@
+// 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.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+using EcmaAssembly = Internal.TypeSystem.Ecma.EcmaAssembly;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ /// <summary>
+ /// Represents a reflectable module.
+ /// </summary>
+ /// <remarks>
+ /// Only expected to be used during ILScanning when scanning for reflection.
+ /// </remarks>
+ internal class ModuleMetadataNode : DependencyNodeCore<NodeFactory>
+ {
+ private readonly ModuleDesc _module;
+
+ public ModuleMetadataNode(ModuleDesc module)
+ {
+ Debug.Assert(module is IAssemblyDesc, "Multi-module assemblies?");
+ _module = module;
+ }
+
+ public ModuleDesc Module => _module;
+
+ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
+ {
+ DependencyList dependencies = new DependencyList();
+
+ // Global module type always generates metadata because it's really convenient to
+ // have something in an assembly that always generates metadata.
+ dependencies.Add(factory.TypeMetadata(_module.GetGlobalModuleType()), "Global module type");
+
+ CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, (EcmaAssembly)_module);
+
+ return dependencies;
+ }
+
+ protected override string GetName(NodeFactory factory)
+ {
+ return "Reflectable module: " + ((IAssemblyDesc)_module).GetName().FullName;
+ }
+
+ public override bool InterestingForDynamicDependencyAnalysis => false;
+ public override bool HasDynamicDependencies => false;
+ public override bool HasConditionalStaticDependencies => false;
+ public override bool StaticDependenciesAreComputed => true;
+ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
+ public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs
index 139204519..8e721c7a3 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs
@@ -435,6 +435,21 @@ namespace ILCompiler.DependencyAnalysis
}
});
+ _typesWithMetadata = new NodeCache<MetadataType, TypeMetadataNode>(type =>
+ {
+ return new TypeMetadataNode(type);
+ });
+
+ _methodsWithMetadata = new NodeCache<MethodDesc, MethodMetadataNode>(method =>
+ {
+ return new MethodMetadataNode(method);
+ });
+
+ _modulesWithMetadata = new NodeCache<ModuleDesc, ModuleMetadataNode>(module =>
+ {
+ return new ModuleMetadataNode(module);
+ });
+
_genericDictionaryLayouts = new NodeCache<TypeSystemEntity, DictionaryLayoutNode>(methodOrType =>
{
return new DictionaryLayoutNode(methodOrType);
@@ -854,6 +869,27 @@ namespace ILCompiler.DependencyAnalysis
}
}
+ private NodeCache<MetadataType, TypeMetadataNode> _typesWithMetadata;
+
+ internal TypeMetadataNode TypeMetadata(MetadataType type)
+ {
+ return _typesWithMetadata.GetOrAdd(type);
+ }
+
+ private NodeCache<MethodDesc, MethodMetadataNode> _methodsWithMetadata;
+
+ internal MethodMetadataNode MethodMetadata(MethodDesc method)
+ {
+ return _methodsWithMetadata.GetOrAdd(method);
+ }
+
+ private NodeCache<ModuleDesc, ModuleMetadataNode> _modulesWithMetadata;
+
+ internal ModuleMetadataNode ModuleMetadata(ModuleDesc module)
+ {
+ return _modulesWithMetadata.GetOrAdd(module);
+ }
+
private NodeCache<string, FrozenStringNode> _frozenStringNodes;
public FrozenStringNode SerializedStringObject(string data)
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataNode.cs
new file mode 100644
index 000000000..a213511c0
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataNode.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.Collections.Generic;
+
+using ILCompiler.DependencyAnalysisFramework;
+
+using Internal.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+using EcmaType = Internal.TypeSystem.Ecma.EcmaType;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ /// <summary>
+ /// Represents a type that has metadata generated in the current compilation.
+ /// </summary>
+ /// <remarks>
+ /// Only expected to be used during ILScanning when scanning for reflection.
+ /// </remarks>
+ internal class TypeMetadataNode : DependencyNodeCore<NodeFactory>
+ {
+ private readonly MetadataType _type;
+
+ public TypeMetadataNode(MetadataType type)
+ {
+ Debug.Assert(type.IsTypeDefinition);
+ _type = type;
+ }
+
+ public MetadataType Type => _type;
+
+ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
+ {
+ DependencyList dependencies = new DependencyList();
+
+ CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, ((EcmaType)_type));
+
+ DefType containingType = _type.ContainingType;
+ if (containingType != null)
+ dependencies.Add(factory.TypeMetadata((MetadataType)containingType), "Containing type of a reflectable type");
+ else
+ dependencies.Add(factory.ModuleMetadata(_type.Module), "Containing module of a reflectable type");
+
+ return dependencies;
+ }
+
+ /// <summary>
+ /// Decomposes a constructed type into individual <see cref="TypeMetadataNode"/> units that will be needed to
+ /// express the constructed type in metadata.
+ /// </summary>
+ public static void GetMetadataDependencies(ref DependencyList dependencies, NodeFactory nodeFactory, TypeDesc type, string reason)
+ {
+ MetadataManager mdManager = nodeFactory.MetadataManager;
+
+ switch (type.Category)
+ {
+ case TypeFlags.Array:
+ case TypeFlags.SzArray:
+ case TypeFlags.ByRef:
+ case TypeFlags.Pointer:
+ GetMetadataDependencies(ref dependencies, nodeFactory, ((ParameterizedType)type).ParameterType, reason);
+ break;
+ case TypeFlags.FunctionPointer:
+ throw new NotImplementedException();
+
+ default:
+ Debug.Assert(type.IsDefType);
+
+ TypeDesc typeDefinition = type.GetTypeDefinition();
+ if (typeDefinition != type)
+ {
+ if (mdManager.CanGenerateMetadata((MetadataType)typeDefinition))
+ {
+ dependencies.Add(nodeFactory.TypeMetadata((MetadataType)typeDefinition), reason);
+ }
+
+ foreach (TypeDesc typeArg in type.Instantiation)
+ {
+ GetMetadataDependencies(ref dependencies, nodeFactory, typeArg, reason);
+ }
+ }
+ else
+ {
+ if (mdManager.CanGenerateMetadata((MetadataType)type))
+ {
+ dependencies.Add(nodeFactory.TypeMetadata((MetadataType)type), reason);
+ }
+ }
+ break;
+ }
+ }
+
+ protected override string GetName(NodeFactory factory)
+ {
+ return "Reflectable type: " + _type.ToString();
+ }
+
+ protected override void OnMarked(NodeFactory factory)
+ {
+ Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_type));
+ Debug.Assert(factory.MetadataManager.CanGenerateMetadata(_type));
+ }
+
+ public override bool InterestingForDynamicDependencyAnalysis => false;
+ public override bool HasDynamicDependencies => false;
+ public override bool HasConditionalStaticDependencies => false;
+ public override bool StaticDependenciesAreComputed => true;
+ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
+ public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs
index d80103870..082268a5f 100644
--- a/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs
@@ -14,7 +14,8 @@ namespace ILCompiler
{
class EmptyMetadataManager : MetadataManager
{
- public EmptyMetadataManager(CompilationModuleGroup group, CompilerTypeSystemContext typeSystemContext) : base(group, typeSystemContext)
+ public EmptyMetadataManager(CompilationModuleGroup group, CompilerTypeSystemContext typeSystemContext)
+ : base(group, typeSystemContext, new FullyBlockedMetadataPolicy())
{
}
@@ -23,11 +24,6 @@ namespace ILCompiler
return Array.Empty<ModuleDesc>();
}
- public override bool IsReflectionBlocked(MetadataType type)
- {
- return true;
- }
-
protected override MetadataCategory GetMetadataCategory(FieldDesc field)
{
return MetadataCategory.None;
@@ -78,5 +74,26 @@ namespace ILCompiler
{
return false;
}
+
+ private sealed class FullyBlockedMetadataPolicy : MetadataBlockingPolicy
+ {
+ public override bool IsBlocked(MetadataType type)
+ {
+ Debug.Assert(type.IsTypeDefinition);
+ return true;
+ }
+
+ public override bool IsBlocked(MethodDesc method)
+ {
+ Debug.Assert(method.IsTypicalMethodDefinition);
+ return true;
+ }
+
+ public override bool IsBlocked(FieldDesc field)
+ {
+ Debug.Assert(field.IsTypicalFieldDefinition);
+ return true;
+ }
+ }
}
}
diff --git a/src/ILCompiler.Compiler/src/Compiler/MetadataBlockingPolicy.cs b/src/ILCompiler.Compiler/src/Compiler/MetadataBlockingPolicy.cs
new file mode 100644
index 000000000..3a2591a28
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/MetadataBlockingPolicy.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 Internal.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler
+{
+ /// <summary>
+ /// Represents a metadata blocking policy. A metadata blocking policy decides what types or members are never
+ /// eligible to have their metadata generated into the executable.
+ /// </summary>
+ public abstract class MetadataBlockingPolicy
+ {
+ /// <summary>
+ /// Returns true if type definition '<paramref name="type"/>' is reflection blocked.
+ /// </summary>
+ public abstract bool IsBlocked(MetadataType type);
+
+ /// <summary>
+ /// Returns true if method definition '<paramref name="method"/>' is reflection blocked.
+ /// </summary>
+ public abstract bool IsBlocked(MethodDesc method);
+
+ /// <summary>
+ /// Returns true if field definition '<paramref name="field"/>' is reflection blocked.
+ /// </summary>
+ public abstract bool IsBlocked(FieldDesc field);
+ }
+
+ /// <summary>
+ /// Represents a metadata policy that blocks implementations details.
+ /// </summary>
+ public sealed class BlockedInternalsBlockingPolicy : MetadataBlockingPolicy
+ {
+ public override bool IsBlocked(MetadataType type)
+ {
+ Debug.Assert(type.IsTypeDefinition);
+
+ // TODO: Make this also respect System.Runtime.CompilerServices.DisablePrivateReflectionAttribute
+ return !(type is Internal.TypeSystem.Ecma.EcmaType);
+ }
+
+ public override bool IsBlocked(MethodDesc method)
+ {
+ Debug.Assert(method.IsTypicalMethodDefinition);
+
+ // TODO: Make this also respect System.Runtime.CompilerServices.DisablePrivateReflectionAttribute
+ return !(method is Internal.TypeSystem.Ecma.EcmaMethod);
+ }
+
+ public override bool IsBlocked(FieldDesc field)
+ {
+ Debug.Assert(field.IsTypicalFieldDefinition);
+
+ // TODO: Make this also respect System.Runtime.CompilerServices.DisablePrivateReflectionAttribute
+ return !(field is Internal.TypeSystem.Ecma.EcmaField);
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
index 3dde1435a..d5021c29c 100644
--- a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs
@@ -37,21 +37,24 @@ namespace ILCompiler
protected readonly CompilationModuleGroup _compilationModuleGroup;
protected readonly CompilerTypeSystemContext _typeSystemContext;
+ protected readonly MetadataBlockingPolicy _blockingPolicy;
private List<NonGCStaticsNode> _cctorContextsGenerated = new List<NonGCStaticsNode>();
private HashSet<TypeDesc> _typesWithEETypesGenerated = new HashSet<TypeDesc>();
private HashSet<TypeDesc> _typesWithConstructedEETypesGenerated = new HashSet<TypeDesc>();
private HashSet<MethodDesc> _methodsGenerated = new HashSet<MethodDesc>();
private HashSet<GenericDictionaryNode> _genericDictionariesGenerated = new HashSet<GenericDictionaryNode>();
+ private List<ModuleDesc> _modulesWithMetadata = new List<ModuleDesc>();
private List<TypeGVMEntriesNode> _typeGVMEntries = new List<TypeGVMEntriesNode>();
internal NativeLayoutInfoNode NativeLayoutInfo { get; private set; }
internal DynamicInvokeTemplateDataNode DynamicInvokeTemplateData { get; private set; }
- public MetadataManager(CompilationModuleGroup compilationModuleGroup, CompilerTypeSystemContext typeSystemContext)
+ public MetadataManager(CompilationModuleGroup compilationModuleGroup, CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy)
{
_compilationModuleGroup = compilationModuleGroup;
_typeSystemContext = typeSystemContext;
+ _blockingPolicy = blockingPolicy;
}
public void AttachToDependencyGraph(DependencyAnalyzerBase<NodeFactory> graph)
@@ -193,6 +196,13 @@ namespace ILCompiler
{
_genericDictionariesGenerated.Add(dictionaryNode);
}
+
+ // 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>
@@ -256,18 +266,36 @@ namespace ILCompiler
protected bool IsMethodSupportedInReflectionInvoke(MethodDesc method)
{
- // TODO: also filter out: .cctor, Finalize, string constructors,
- // RuntimeHelpers.InitializeArray, methods on Nullable,
- // IntPtr/UIntPtr constructors. Maybe more.
+ TypeDesc owningType = method.OwningType;
- // ----------------------------------------------------------------
- // Delegate construction is only allowed through specific IL sequences
- // ----------------------------------------------------------------
+ // Methods on nullable are special cased in the runtime reflection
+ if (owningType.IsNullable)
+ return false;
+
+ // Finalizers are not reflection invokable
+ if (method.IsFinalizer)
+ return false;
- if (method.OwningType.IsDelegate && method.IsConstructor)
+ // Static constructors are not reflection invokable
+ if (method.IsStaticConstructor)
return false;
- // Everything else should get a stub.
+ if (method.IsConstructor)
+ {
+ // Delegate construction is only allowed through specific IL sequences
+ if (owningType.IsDelegate)
+ return false;
+
+ // String constructors are intrinsic and special cased in runtime reflection
+ if (owningType.IsString)
+ return false;
+
+ // IntPtr/UIntPtr constructors are intrinsic and special cased in runtime reflection
+ if (owningType.IsWellKnownType(WellKnownType.IntPtr) || owningType.IsWellKnownType(WellKnownType.UIntPtr))
+ return false;
+ }
+
+ // Everything else can go in the mapping table.
return true;
}
@@ -479,7 +507,11 @@ namespace ILCompiler
/// <summary>
/// Returns a set of modules that will get some metadata emitted into the output module
/// </summary>
- public abstract IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata();
+ public virtual IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata()
+ {
+ // TODO: this is temporary until we have a metadata manager for IL scanner. This method should be abstract.
+ return _modulesWithMetadata;
+ }
public byte[] GetMetadataBlob(NodeFactory factory)
{
@@ -540,9 +572,109 @@ namespace ILCompiler
return _typesWithConstructedEETypesGenerated;
}
- public abstract bool IsReflectionBlocked(MetadataType type);
+ public bool IsReflectionBlocked(TypeDesc type)
+ {
+ switch (type.Category)
+ {
+ case TypeFlags.SzArray:
+ case TypeFlags.Array:
+ case TypeFlags.Pointer:
+ case TypeFlags.ByRef:
+ return IsReflectionBlocked(((ParameterizedType)type).ParameterType);
+
+ case TypeFlags.FunctionPointer:
+ throw new NotImplementedException();
+
+ default:
+ Debug.Assert(type.IsDefType);
+
+ TypeDesc typeDefinition = type.GetTypeDefinition();
+ if (type != typeDefinition)
+ {
+ if (_blockingPolicy.IsBlocked((MetadataType)typeDefinition))
+ return true;
+
+ foreach (var arg in type.Instantiation)
+ if (IsReflectionBlocked(arg))
+ return true;
+
+ return false;
+ }
+
+ if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
+ return false;
+ return _blockingPolicy.IsBlocked((MetadataType)type);
+ }
+ }
+
+ public bool IsReflectionBlocked(FieldDesc field)
+ {
+ FieldDesc typicalFieldDefinition = field.GetTypicalFieldDefinition();
+ if (typicalFieldDefinition != field)
+ {
+ foreach (TypeDesc type in field.OwningType.Instantiation)
+ {
+ if (IsReflectionBlocked(type))
+ return true;
+ }
+ }
+
+ return _blockingPolicy.IsBlocked(typicalFieldDefinition);
+ }
+
+ public bool IsReflectionBlocked(MethodDesc method)
+ {
+ MethodDesc methodDefinition = method.GetMethodDefinition();
+ if (method != methodDefinition)
+ {
+ foreach (TypeDesc type in method.Instantiation)
+ {
+ if (IsReflectionBlocked(type))
+ return true;
+ }
+ }
+
+ MethodDesc typicalMethodDefinition = methodDefinition.GetTypicalMethodDefinition();
+ if (typicalMethodDefinition != methodDefinition)
+ {
+ foreach (TypeDesc type in method.OwningType.Instantiation)
+ {
+ if (IsReflectionBlocked(type))
+ return true;
+ }
+ }
+
+ return _blockingPolicy.IsBlocked(typicalMethodDefinition);
+ }
+
+ public bool CanGenerateMetadata(MetadataType type)
+ {
+ return (GetMetadataCategory(type) & MetadataCategory.Description) != 0;
+ }
+
+ public bool CanGenerateMetadata(MethodDesc method)
+ {
+ Debug.Assert(method.IsTypicalMethodDefinition);
+ return (GetMetadataCategory(method) & MetadataCategory.Description) != 0;
+ }
+
+ /// <summary>
+ /// Gets the metadata category for a compiled method body in the current compilation.
+ /// The method will only get called with '<paramref name="method"/>' that has a compiled method body
+ /// in this compilation.
+ /// Note that if this method doesn't return <see cref="MetadataCategory.Description"/>, it doesn't mean
+ /// that the method never has metadata. The metadata might just be generated in a different compilation.
+ /// </summary>
protected abstract MetadataCategory GetMetadataCategory(MethodDesc method);
+
+ /// <summary>
+ /// Gets the metadata category for a generated type in the current compilation.
+ /// The method can assume it will only get called with '<paramref name="type"/>' that has an EEType generated
+ /// in the current compilation.
+ /// Note that if this method doesn't return <see cref="MetadataCategory.Description"/>, it doesn't mean
+ /// that the method never has metadata. The metadata might just be generated in a different compilation.
+ /// </summary>
protected abstract MetadataCategory GetMetadataCategory(TypeDesc type);
protected abstract MetadataCategory GetMetadataCategory(FieldDesc field);
}
@@ -559,6 +691,7 @@ namespace ILCompiler
}
}
+ [Flags]
public enum MetadataCategory
{
None = 0x00,
diff --git a/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs
index 942e85ba5..9a6765dbe 100644
--- a/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs
@@ -42,7 +42,8 @@ namespace ILCompiler
private Lazy<Dictionary<MethodDesc, MethodDesc>> _dynamicInvokeStubs;
private readonly byte[] _metadataBlob;
- public PrecomputedMetadataManager(CompilationModuleGroup group, CompilerTypeSystemContext typeSystemContext, ModuleDesc metadataDescribingModule, IEnumerable<ModuleDesc> compilationModules, byte[] metadataBlob) : base(group, typeSystemContext)
+ public PrecomputedMetadataManager(CompilationModuleGroup group, CompilerTypeSystemContext typeSystemContext, ModuleDesc metadataDescribingModule, IEnumerable<ModuleDesc> compilationModules, byte[] metadataBlob)
+ : base(group, typeSystemContext, new AttributeSpecifiedBlockingPolicy())
{
_metadataDescribingModule = metadataDescribingModule;
_compilationModules = new HashSet<ModuleDesc>(compilationModules);
@@ -187,11 +188,6 @@ namespace ILCompiler
return _loadedMetadata.Value.LocalMetadataModules;
}
- public override bool IsReflectionBlocked(MetadataType type)
- {
- return type.HasCustomAttribute("System.Runtime.CompilerServices", "ReflectionBlockedAttribute");
- }
-
public override bool WillUseMetadataTokenToReferenceMethod(MethodDesc method)
{
return _compilationModuleGroup.ContainsType(method.GetTypicalMethodDefinition().OwningType);
@@ -449,5 +445,28 @@ namespace ILCompiler
return dynamicInvokeStubCanonicalized;
}
+
+ private sealed class AttributeSpecifiedBlockingPolicy : MetadataBlockingPolicy
+ {
+ public override bool IsBlocked(MetadataType type)
+ {
+ Debug.Assert(type.IsTypeDefinition);
+ return type.HasCustomAttribute("System.Runtime.CompilerServices", "ReflectionBlockedAttribute");
+ }
+
+ public override bool IsBlocked(MethodDesc method)
+ {
+ Debug.Assert(method.IsTypicalMethodDefinition);
+ // TODO: we might need to do something here if we keep this policy.
+ return false;
+ }
+
+ public override bool IsBlocked(FieldDesc field)
+ {
+ Debug.Assert(field.IsTypicalFieldDefinition);
+ // TODO: we might need to do something here if we keep this policy.
+ return false;
+ }
+ }
}
}
diff --git a/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs b/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs
index 58850e22c..20d9b497f 100644
--- a/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs
@@ -74,9 +74,7 @@ namespace ILCompiler
if (_generateDebugInfo)
jitFlagBuilder.Add(CorJitFlag.CORJIT_FLAG_DEBUG_INFO);
- MetadataManager metadataManager = CreateMetadataManager();
-
- var factory = new RyuJitNodeFactory(_context, _compilationGroup, metadataManager, _nameMangler);
+ var factory = new RyuJitNodeFactory(_context, _compilationGroup, _metadataManager, _nameMangler);
var jitConfig = new JitConfigProvider(jitFlagBuilder.ToArray(), _ryujitOptions);
DependencyAnalyzerBase<NodeFactory> graph = CreateDependencyGraph(factory);
diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
index 966f7e972..f780e292c 100644
--- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
+++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
@@ -112,13 +112,18 @@
<Compile Include="Compiler\CompilerTypeSystemContext.BoxedTypes.cs" />
<Compile Include="Compiler\CompilerTypeSystemContext.Mangling.cs" />
<Compile Include="Compiler\CompilerTypeSystemContext.Sorting.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\CustomAttributeBasedDependencyAlgorithm.cs" />
<Compile Include="Compiler\DependencyAnalysis\ILScanNodeFactory.cs" />
<Compile Include="Compiler\PreInitFieldInfo.cs" />
<Compile Include="Compiler\DependencyAnalysis\FrozenArrayNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\GCStaticsPreInitDataNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ImportedGenericDictionaryNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\DynamicInvokeTemplateDataNode.cs" />
+ <Compile Include="Compiler\MetadataBlockingPolicy.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\MethodMetadataNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReflectableMethodNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\ModuleMetadataNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\TypeMetadataNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ScannedMethodNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ShadowConcreteUnboxingThunkNode.cs" />
<Compile Include="Compiler\DependencyTrackingLevel.cs" />
diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs
index 0ad6851c0..7ea68e212 100644
--- a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs
+++ b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs
@@ -29,8 +29,7 @@ namespace ILCompiler
public override ICompilation ToCompilation()
{
- MetadataManager metadataManager = CreateMetadataManager();
- CppCodegenNodeFactory factory = new CppCodegenNodeFactory(_context, _compilationGroup, metadataManager, _nameMangler);
+ CppCodegenNodeFactory factory = new CppCodegenNodeFactory(_context, _compilationGroup, _metadataManager, _nameMangler);
DependencyAnalyzerBase<NodeFactory> graph = CreateDependencyGraph(factory);
return new CppCodegenCompilation(graph, factory, _compilationRoots, _logger, _config);
diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs
index ccb52f9c4..28d02f8be 100644
--- a/src/ILCompiler/src/Program.cs
+++ b/src/ILCompiler/src/Program.cs
@@ -335,14 +335,16 @@ namespace ILCompiler
DependencyTrackingLevel trackingLevel = _dgmlLogFileName == null ?
DependencyTrackingLevel.None : (_generateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
+ CompilerGeneratedMetadataManager metadataManager = new CompilerGeneratedMetadataManager(compilationGroup, typeSystemContext, _metadataLogFileName);
+
ICompilation compilation = builder
.UseBackendOptions(_codegenOptions)
+ .UseMetadataManager(metadataManager)
.UseLogger(logger)
.UseDependencyTracking(trackingLevel)
.UseCompilationRoots(compilationRoots)
.UseOptimizationMode(_optimizationMode)
.UseDebugInfo(_enableDebugInfo)
- .UseMetadataLogFile(_metadataLogFileName)
.ToCompilation();
ObjectDumper dumper = _mapFileName != null ? new ObjectDumper(_mapFileName) : null;