|
// 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 System.Reflection;
using System.Reflection.Metadata;
using ILCompiler.Dataflow;
using ILCompiler.DependencyAnalysisFramework;
using ILCompiler.Logging;
using Internal.TypeSystem;
using Debug = System.Diagnostics.Debug;
using EcmaMethod = Internal.TypeSystem.Ecma.EcmaMethod;
using EcmaType = Internal.TypeSystem.Ecma.EcmaType;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a method that has metadata generated in the current compilation.
/// This corresponds to a ECMA-335 MethodDef record. It is however not a 1:1
/// mapping because a method could be used in the AOT compiled program without generating
/// the reflection metadata for it (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 MethodMetadataNode : DependencyNodeCore<NodeFactory>
{
private readonly EcmaMethod _method;
private readonly bool _isMinimal;
public MethodMetadataNode(MethodDesc method, bool isMinimal)
{
Debug.Assert(method.IsTypicalMethodDefinition);
_method = (EcmaMethod)method;
_isMinimal = isMinimal;
}
public MethodDesc Method => _method;
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
DependencyList dependencies = new DependencyList();
var owningType = (MetadataType)_method.OwningType;
dependencies.Add(factory.TypeMetadata(owningType), "Owning type metadata");
if (!_isMinimal)
{
foreach (var parameterHandle in _method.MetadataReader.GetMethodDefinition(_method.Handle).GetParameters())
{
dependencies.Add(factory.MethodParameterMetadata(new ReflectableParameter(_method.Module, parameterHandle)), "Parameter is visible");
}
}
MethodSignature sig = _method.Signature;
const string reason = "Method signature metadata";
TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, sig.ReturnType, reason);
foreach (TypeDesc paramType in sig)
{
TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, paramType, reason);
}
if (sig.HasEmbeddedSignatureData)
{
foreach (var sigData in sig.GetEmbeddedSignatureData())
if (sigData.type != null)
TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, sigData.type, "Modifier in a method signature");
}
if (!_isMinimal)
{
DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, _method);
// On a reflectable method, perform generic data flow for the return type and all the parameter types
// This is a compensation for the DI issue described in https://github.com/dotnet/runtime/issues/81358
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(ref dependencies, factory, new MessageOrigin(_method), _method.Signature.ReturnType, _method);
foreach (TypeDesc parameterType in _method.Signature)
{
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(ref dependencies, factory, new MessageOrigin(_method), parameterType, _method);
}
if (_method.HasCustomAttribute("System.Diagnostics", "StackTraceHiddenAttribute")
|| owningType.HasCustomAttribute("System.Diagnostics", "StackTraceHiddenAttribute"))
{
dependencies.Add(factory.AnalysisCharacteristic("StackTraceHiddenMetadataPresent"), "Method is StackTraceHidden");
}
// If this method is a property or event accessor, ensure metadata for the associated
// property or event is generated as well. Properties/events are not modeled as first-class
// entities in the type system, so we discover them here from their accessors.
// As a performance optimization, only SpecialName methods can be accessors.
if ((_method.Attributes & MethodAttributes.SpecialName) != 0)
{
MetadataReader reader = _method.MetadataReader;
MethodDefinitionHandle methodHandle = _method.Handle;
TypeDefinition declaringType = reader.GetTypeDefinition(reader.GetMethodDefinition(methodHandle).GetDeclaringType());
foreach (PropertyDefinitionHandle propertyHandle in declaringType.GetProperties())
{
PropertyAccessors accessors = reader.GetPropertyDefinition(propertyHandle).GetAccessors();
if (accessors.Getter == methodHandle || accessors.Setter == methodHandle)
{
dependencies.Add(
factory.PropertyMetadata(new PropertyPseudoDesc((EcmaType)owningType, propertyHandle)),
"Property associated with reflectable accessor");
}
}
foreach (EventDefinitionHandle eventHandle in declaringType.GetEvents())
{
EventAccessors accessors = reader.GetEventDefinition(eventHandle).GetAccessors();
if (accessors.Adder == methodHandle || accessors.Remover == methodHandle || accessors.Raiser == methodHandle)
{
dependencies.Add(
factory.EventMetadata(new EventPseudoDesc((EcmaType)owningType, eventHandle)),
"Event associated with reflectable accessor");
}
}
}
}
return dependencies;
}
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
{
var dependencies = new List<CombinedDependencyListEntry>();
CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, _method);
return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Method metadata: " + _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 => !_isMinimal;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
|