| File: Compiler\DependencyAnalysis\TypeMetadataNode.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. 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. /// This node corresponds to an ECMA-335 TypeDef record. It is however not a 1:1 /// mapping because IL could be compiled into machine code without generating a record /// in the reflection metadata (which would not be possible in IL terms). /// </summary> /// <remarks> /// Only expected to be used during ILScanning when scanning for reflection. /// </remarks> internal sealed 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(); MetadataType containingType = _type.ContainingType; if (containingType != null) dependencies.Add(factory.TypeMetadata(containingType), "Containing type of a reflectable type"); else dependencies.Add(factory.ModuleMetadata(_type.Module), "Containing module of a reflectable type"); MetadataType baseType = _type.BaseType; if (baseType != null) GetMetadataDependencies(ref dependencies, factory, baseType, "Base type of a reflectable type"); var mdManager = (UsageBasedMetadataManager)factory.MetadataManager; if (_type.IsEnum) { // A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type), // so for enums also include their MethodTable. dependencies.Add(factory.ReflectedType(_type), "Reflectable enum"); // Enums are not useful without their literal fields. The literal fields are not referenced // from anywhere (source code reference to enums compiles to the underlying numerical constants in IL). foreach (FieldDesc enumField in _type.GetFields()) { if (enumField.IsLiteral) { dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum"); } } } // If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that. if ((mdManager._generationOptions & UsageBasedMetadataGenerationOptions.CompleteTypesOnly) != 0) { foreach (MethodDesc method in _type.GetMethods()) { if (!mdManager.IsReflectionBlocked(method)) { try { // Spot check by parsing signature. // Previously we had LibraryRootProvider.CheckCanGenerateMethod(method) here, but that one // expects fully instantiated types and methods. We operate on definitions here. // This is not as thorough as it could be. This option is unsupported anyway. _ = method.Signature; } catch (TypeSystemException) { continue; } dependencies.Add(factory.MethodMetadata(method), "Complete metadata for type"); } } foreach (FieldDesc field in _type.GetFields()) { if (!mdManager.IsReflectionBlocked(field)) dependencies.Add(factory.FieldMetadata(field), "Complete metadata for type"); } } return dependencies; } public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) { var dependencies = new List<CombinedDependencyListEntry>(); CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, ((EcmaType)_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: var pointerType = (FunctionPointerType)type; GetMetadataDependencies(ref dependencies, nodeFactory, pointerType.Signature.ReturnType, reason); foreach (TypeDesc paramType in pointerType.Signature) GetMetadataDependencies(ref dependencies, nodeFactory, paramType, reason); break; case TypeFlags.SignatureMethodVariable: case TypeFlags.SignatureTypeVariable: break; default: Debug.Assert(type.IsDefType); // We generally postpone creating MethodTables until absolutely needed. // IDynamicInterfaceCastableImplementation is special in the sense that just obtaining a System.Type // (by e.g. browsing custom attribute metadata) gives the user enough to pass this to runtime APIs // that need a MethodTable. We don't have a legitimate type handle without the MethodTable. Other // kinds of APIs that expect a MethodTable have enough dataflow annotation to trigger warnings. // There's no dataflow annotations on the IDynamicInterfaceCastable.GetInterfaceImplementation API. if (type.IsInterface && ((MetadataType)type).IsDynamicInterfaceCastableImplementation()) { dependencies ??= new DependencyList(); dependencies.Add(nodeFactory.ReflectedType(type), "Reflected IDynamicInterfaceCastableImplementation"); } TypeDesc typeDefinition = type.GetTypeDefinition(); if (typeDefinition != type) { if (mdManager.CanGenerateMetadata((MetadataType)typeDefinition)) { dependencies ??= new DependencyList(); 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 ??= new DependencyList(); dependencies.Add(nodeFactory.TypeMetadata((MetadataType)type), reason); } } break; } } protected override string GetName(NodeFactory factory) { return "Type metadata: " + _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 => true; public override bool StaticDependenciesAreComputed => true; public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null; } }