|
// 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;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// The field can be on a non-generic type, generic type definition, or an instantiatied type.
/// To match IL semantics, we maintain that a field on a generic type will be consistently
/// reflection-accessible. Either the field is accessible on all instantiations or on none of them.
/// </summary>
public class ReflectedFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;
public ReflectedFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}
public FieldDesc Field => _field;
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));
DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);
// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}
// readonly static fields are not reflection settable, the rest are
if (!_field.IsInitOnly || !_field.IsStatic)
dependencies.Add(factory.NotReadOnlyField(_field), "Reflection writable field");
FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectedField(typicalField), "Definition of the reflectable field");
}
// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");
// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);
if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex(_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol(_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol(_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol(_field.OwningType), "CCtor context");
}
// For generic types, the reflection mapping table only keeps track of information about offsets
// from the static bases. To locate the static base, we need the GenericStaticBaseInfo hashtable.
if (_field.OwningType.HasInstantiation)
{
dependencies.Add(factory.GenericStaticBaseInfo(_field.OwningType), "Field on a generic type");
}
}
TypeDesc fieldType = _field.FieldType.NormalizeInstantiation();
ReflectionInvokeMapNode.AddSignatureDependency(ref dependencies, factory, _field, fieldType, "Type of the field", isOut: true);
return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}
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;
}
}
|