Skip to content

Commit

Permalink
Make TypeComponentsCache trimmable (dotnet#80726)
Browse files Browse the repository at this point in the history
Contributes to dotnet#80165.

Dispensing of reflection member infos is done through a member policies class. This is a generic class that has specialized implementations for each kind of member info.

It used a clever trick to get to the specific implementations. Just access `MemberPolicies<EventInfo>.Default` to get one for events or `MemberPolicies<PropertyInfo>.Default` to get one for properties. It was also absolutely not trimming friendly.

This change removes the clever trick and replaces it with good old fashioned parameter passing.
  • Loading branch information
MichalStrehovsky authored and mdh1418 committed Jan 24, 2023
1 parent baaff52 commit e63ba0c
Show file tree
Hide file tree
Showing 15 changed files with 102 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//==========================================================================================================================
internal sealed class ConstructorPolicies : MemberPolicies<ConstructorInfo>
{
public static readonly ConstructorPolicies Instance = new ConstructorPolicies();

public ConstructorPolicies() : base(MemberTypeIndex.Constructor) { }

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<ConstructorInfo> GetDeclaredMembers(TypeInfo typeInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//==========================================================================================================================
internal sealed class EventPolicies : MemberPolicies<EventInfo>
{
public static readonly EventPolicies Instance = new EventPolicies();

public EventPolicies() : base(MemberTypeIndex.Event) { }

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<EventInfo> GetDeclaredMembers(TypeInfo typeInfo)
Expand Down Expand Up @@ -67,7 +71,7 @@ public sealed override bool ImplicitlyOverrides(EventInfo? baseMember, EventInfo
{
MethodInfo? baseAccessor = GetAccessorMethod(baseMember!);
MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!);
return MemberPolicies<MethodInfo>.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor);
return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor);
}

public sealed override bool OkToIgnoreAmbiguity(EventInfo m1, EventInfo m2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//==========================================================================================================================
internal sealed class FieldPolicies : MemberPolicies<FieldInfo>
{
public static readonly FieldPolicies Instance = new FieldPolicies();

public FieldPolicies() : base(MemberTypeIndex.Field) { }

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<FieldInfo> GetDeclaredMembers(TypeInfo typeInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//=================================================================================================================
internal abstract class MemberPolicies<M> where M : MemberInfo
{
public MemberPolicies(int index)
{
Index = index;
}

//=================================================================================================================
// Subclasses for specific MemberInfo types must override these:
//=================================================================================================================
Expand Down Expand Up @@ -184,55 +189,11 @@ private static bool GenericMethodAwareAreParameterTypesEqual(Type t1, Type t2)
return false;
}

static MemberPolicies()
{
Type t = typeof(M);
if (t.Equals(typeof(FieldInfo)))
{
MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Field;
Default = (MemberPolicies<M>)(object)(new FieldPolicies());
}
else if (t.Equals(typeof(MethodInfo)))
{
MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Method;
Default = (MemberPolicies<M>)(object)(new MethodPolicies());
}
else if (t.Equals(typeof(ConstructorInfo)))
{
MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Constructor;
Default = (MemberPolicies<M>)(object)(new ConstructorPolicies());
}
else if (t.Equals(typeof(PropertyInfo)))
{
MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Property; ;
Default = (MemberPolicies<M>)(object)(new PropertyPolicies());
}
else if (t.Equals(typeof(EventInfo)))
{
MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.Event;
Default = (MemberPolicies<M>)(object)(new EventPolicies());
}
else if (t.Equals(typeof(Type)))
{
MemberTypeIndex = BindingFlagSupport.MemberTypeIndex.NestedType;
Default = (MemberPolicies<M>)(object)(new NestedTypePolicies());
}
else
{
Debug.Fail("Unknown MemberInfo type.");
}
}

//
// This is a singleton class one for each MemberInfo category: Return the appropriate one.
//
public static readonly MemberPolicies<M> Default;

//
// This returns a fixed value from 0 to MemberIndex.Count-1 with each possible type of M
// being assigned a unique index (see the MemberTypeIndex for possible values). This is useful
// for converting a type reference to M to an array index or switch case label.
//
public static readonly int MemberTypeIndex;
public int Index { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//==========================================================================================================================
internal sealed class MethodPolicies : MemberPolicies<MethodInfo>
{
public static readonly MethodPolicies Instance = new MethodPolicies();

public MethodPolicies() : base(MemberTypeIndex.Method) { }

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<MethodInfo> GetDeclaredMembers(TypeInfo typeInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//==========================================================================================================================
internal sealed class NestedTypePolicies : MemberPolicies<Type>
{
public static readonly NestedTypePolicies Instance = new NestedTypePolicies();

public NestedTypePolicies() : base(MemberTypeIndex.NestedType) { }

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<Type> GetDeclaredMembers(TypeInfo typeInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//==========================================================================================================================
internal sealed class PropertyPolicies : MemberPolicies<PropertyInfo>
{
public static readonly PropertyPolicies Instance = new PropertyPolicies();

public PropertyPolicies() : base(MemberTypeIndex.Property) { }

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "Reflection implementation")]
public sealed override IEnumerable<PropertyInfo> GetDeclaredMembers(TypeInfo typeInfo)
Expand Down Expand Up @@ -54,7 +58,7 @@ public sealed override bool ImplicitlyOverrides(PropertyInfo? baseMember, Proper
{
MethodInfo? baseAccessor = GetAccessorMethod(baseMember!);
MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!);
return MemberPolicies<MethodInfo>.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor);
return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor);
}

//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,10 @@ public QueriedMemberList<M> Filter(Func<M, bool> predicate)
//
// Filter by name and visibility from the ReflectedType.
//
public static QueriedMemberList<M> Create(RuntimeTypeInfo type, string optionalNameFilter, bool ignoreCase)
public static QueriedMemberList<M> Create(MemberPolicies<M> policies, RuntimeTypeInfo type, string optionalNameFilter, bool ignoreCase)
{
RuntimeTypeInfo reflectedType = type;

MemberPolicies<M> policies = MemberPolicies<M>.Default;

NameFilter? nameFilter;
if (optionalNameFilter == null)
nameFilter = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ namespace System.Reflection.Runtime.BindingFlagSupport
//
internal partial struct QueryResult<M> where M : MemberInfo
{
public QueryResult(BindingFlags bindingAttr, QueriedMemberList<M> queriedMembers)
public QueryResult(MemberPolicies<M> policies, BindingFlags bindingAttr, QueriedMemberList<M> queriedMembers)
{
_policies = policies;
_lazyCount = 0;
_bindingAttr = bindingAttr;
_queriedMembers = queriedMembers;
Expand Down Expand Up @@ -114,8 +115,7 @@ public void CopyTo(MemberInfo[] array, int startIndex)
if (match.DeclaringType.Equals(challenger.DeclaringType))
throw new AmbiguousMatchException();

MemberPolicies<M> policies = MemberPolicies<M>.Default;
if (!policies.OkToIgnoreAmbiguity(match, challenger))
if (!_policies.OkToIgnoreAmbiguity(match, challenger))
throw new AmbiguousMatchException();
}
else
Expand All @@ -129,6 +129,7 @@ public void CopyTo(MemberInfo[] array, int startIndex)

private int UnfilteredCount => ((_bindingAttr & BindingFlags.DeclaredOnly) != 0) ? _queriedMembers.DeclaredOnlyCount : _queriedMembers.TotalCount;

private readonly MemberPolicies<M> _policies;
private readonly BindingFlags _bindingAttr;
private int _lazyCount; // Intentionally not marking as volatile. QueryResult is for short-term use within a single method call - no aspiration to be thread-safe.
private QueriedMemberList<M> _queriedMembers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,8 @@ public static bool QualifiesBasedOnParameterCount(this MethodBase methodBase, Bi
// - MethodImpls ignored. (I didn't say it made sense, this is just how the desktop api we're porting behaves.)
// - Implemented interfaces ignores. (I didn't say it made sense, this is just how the desktop api we're porting behaves.)
//
public static M GetImplicitlyOverriddenBaseClassMember<M>(this M member) where M : MemberInfo
public static M GetImplicitlyOverriddenBaseClassMember<M>(this M member, MemberPolicies<M> policies) where M : MemberInfo
{
MemberPolicies<M> policies = MemberPolicies<M>.Default;
bool isVirtual;
bool isNewSlot;
policies.GetMemberAttributes(member, out _, out _, out isVirtual, out isNewSlot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,17 @@ public sealed override FieldInfo GetFieldFromHandle(RuntimeFieldHandle runtimeFi

public sealed override EventInfo GetImplicitlyOverriddenBaseClassEvent(EventInfo e)
{
return e.GetImplicitlyOverriddenBaseClassMember();
return e.GetImplicitlyOverriddenBaseClassMember(EventPolicies.Instance);
}

public sealed override MethodInfo GetImplicitlyOverriddenBaseClassMethod(MethodInfo m)
{
return m.GetImplicitlyOverriddenBaseClassMember();
return m.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance);
}

public sealed override PropertyInfo GetImplicitlyOverriddenBaseClassProperty(PropertyInfo p)
{
return p.GetImplicitlyOverriddenBaseClassMember();
return p.GetImplicitlyOverriddenBaseClassMember(PropertyPolicies.Instance);
}

private static FieldInfo GetFieldInfo(RuntimeTypeHandle declaringTypeHandle, FieldHandle fieldHandle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public sealed override MethodInfo GetBaseDefinition()

while (true)
{
MethodInfo next = method.GetImplicitlyOverriddenBaseClassMember();
MethodInfo next = method.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance);
if (next == null)
return ((RuntimeMethodInfo)method).WithReflectedTypeSetToDeclaringType;

Expand Down
Loading

0 comments on commit e63ba0c

Please sign in to comment.