Skip to content

Commit

Permalink
Revert "Avoid a few array allocations with DefaultBinder (#93115)" (#…
Browse files Browse the repository at this point in the history
…95872)

This reverts commit 565ee96.
  • Loading branch information
stephentoub authored Dec 12, 2023
1 parent d4bfbf1 commit 0fae364
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeTy
Debug.Assert(target is not null);

IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
PseudoCustomAttribute.GetCustomAttributes(target, (RuntimeType)typeof(object), ref pcas);
return pcas.Count > 0 ? GetCombinedList(cad, ref pcas) : cad;
}
Expand All @@ -28,7 +28,7 @@ internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeFi
Debug.Assert(target is not null);

IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
PseudoCustomAttribute.GetCustomAttributes(target, (RuntimeType)typeof(object), ref pcas);
return pcas.Count > 0 ? GetCombinedList(cad, ref pcas) : cad;
}
Expand All @@ -38,7 +38,7 @@ internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeMe
Debug.Assert(target is not null);

IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
PseudoCustomAttribute.GetCustomAttributes(target, (RuntimeType)typeof(object), ref pcas);
return pcas.Count > 0 ? GetCombinedList(cad, ref pcas) : cad;
}
Expand Down Expand Up @@ -87,13 +87,13 @@ internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimePa
{
Debug.Assert(target is not null);

ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule()!, target.MetadataToken);
PseudoCustomAttribute.GetCustomAttributes(target, (RuntimeType)typeof(object), ref pcas);
return pcas.Count > 0 ? GetCombinedList(cad, ref pcas) : cad;
}

private static ReadOnlyCollection<CustomAttributeData> GetCombinedList(IList<CustomAttributeData> customAttributes, ref ListBuilder<Attribute> pseudoAttributes)
private static ReadOnlyCollection<CustomAttributeData> GetCombinedList(IList<CustomAttributeData> customAttributes, ref RuntimeType.ListBuilder<Attribute> pseudoAttributes)
{
Debug.Assert(pseudoAttributes.Count != 0);

Expand Down Expand Up @@ -922,7 +922,7 @@ internal static object[] GetCustomAttributes(RuntimeType type, RuntimeType caTyp
if (type.IsGenericType && !type.IsGenericTypeDefinition)
type = (type.GetGenericTypeDefinition() as RuntimeType)!;

ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
PseudoCustomAttribute.GetCustomAttributes(type, caType, ref pcas);

// if we are asked to go up the hierarchy chain we have to do it now and regardless of the
Expand All @@ -935,7 +935,7 @@ internal static object[] GetCustomAttributes(RuntimeType type, RuntimeType caTyp
return attributes;
}

ListBuilder<object> result = default;
RuntimeType.ListBuilder<object> result = default;
bool mustBeInheritable = false;

for (int i = 0; i < pcas.Count; i++)
Expand Down Expand Up @@ -964,7 +964,7 @@ internal static object[] GetCustomAttributes(RuntimeMethodInfo method, RuntimeTy
if (method.IsGenericMethod && !method.IsGenericMethodDefinition)
method = (method.GetGenericMethodDefinition() as RuntimeMethodInfo)!;

ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
PseudoCustomAttribute.GetCustomAttributes(method, caType, ref pcas);

// if we are asked to go up the hierarchy chain we have to do it now and regardless of the
Expand All @@ -977,7 +977,7 @@ internal static object[] GetCustomAttributes(RuntimeMethodInfo method, RuntimeTy
return attributes;
}

ListBuilder<object> result = default;
RuntimeType.ListBuilder<object> result = default;
bool mustBeInheritable = false;

for (int i = 0; i < pcas.Count; i++)
Expand Down Expand Up @@ -1033,7 +1033,7 @@ internal static object[] GetCustomAttributes(RuntimeFieldInfo field, RuntimeType
Debug.Assert(field is not null);
Debug.Assert(caType is not null);

ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
PseudoCustomAttribute.GetCustomAttributes(field, caType, ref pcas);
object[] attributes = GetCustomAttributes(field.GetRuntimeModule(), field.MetadataToken, pcas.Count, caType);
if (pcas.Count > 0) pcas.CopyTo(attributes, attributes.Length - pcas.Count);
Expand All @@ -1045,7 +1045,7 @@ internal static object[] GetCustomAttributes(RuntimeParameterInfo parameter, Run
Debug.Assert(parameter is not null);
Debug.Assert(caType is not null);

ListBuilder<Attribute> pcas = default;
RuntimeType.ListBuilder<Attribute> pcas = default;
PseudoCustomAttribute.GetCustomAttributes(parameter, caType, ref pcas);
object[] attributes = GetCustomAttributes(parameter.GetRuntimeModule()!, parameter.MetadataToken, pcas.Count, caType);
if (pcas.Count > 0) pcas.CopyTo(attributes, attributes.Length - pcas.Count);
Expand Down Expand Up @@ -1101,7 +1101,7 @@ private static bool IsCustomAttributeDefined(
{
Debug.Assert(attributeCtorToken == 0);

ListBuilder<object> derivedAttributes = default;
RuntimeType.ListBuilder<object> derivedAttributes = default;

for (int i = 0; i < attributeTokens.Length; i++)
{
Expand Down Expand Up @@ -1139,7 +1139,7 @@ private static bool IsCustomAttributeDefined(
private static object[] GetCustomAttributes(
RuntimeModule decoratedModule, int decoratedMetadataToken, int pcaCount, RuntimeType attributeFilterType)
{
ListBuilder<object> attributes = default;
RuntimeType.ListBuilder<object> attributes = default;

AddCustomAttributes(ref attributes, decoratedModule, decoratedMetadataToken, attributeFilterType, false, default);

Expand All @@ -1156,11 +1156,11 @@ private static object[] GetCustomAttributes(
"attribute instantiation which is present in the code linker has analyzed." +
"As such the reflection usage in this method will never fail as those methods/fields will be present.")]
private static void AddCustomAttributes(
ref ListBuilder<object> attributes,
ref RuntimeType.ListBuilder<object> attributes,
RuntimeModule decoratedModule, int decoratedMetadataToken,
RuntimeType? attributeFilterType, bool mustBeInheritable,
// The derivedAttributes list must be passed by value so that it is not modified with the discovered attributes
ListBuilder<object> derivedAttributes)
RuntimeType.ListBuilder<object> derivedAttributes)
{
CustomAttributeRecord[] car = RuntimeCustomAttributeData.GetCustomAttributeRecords(decoratedModule, decoratedMetadataToken);

Expand Down Expand Up @@ -1295,7 +1295,7 @@ private static bool FilterCustomAttributeRecord(
MetadataToken decoratedToken,
RuntimeType attributeFilterType,
bool mustBeInheritable,
ref ListBuilder<object> derivedAttributes,
ref RuntimeType.ListBuilder<object> derivedAttributes,
out RuntimeType attributeType,
out IRuntimeMethodInfo? ctorWithParameters,
out bool isVarArg)
Expand Down Expand Up @@ -1409,7 +1409,7 @@ private static bool MatchesTypeFilter(RuntimeType attributeType, RuntimeType att

#region Private Static Methods
private static bool AttributeUsageCheck(
RuntimeType attributeType, bool mustBeInheritable, ref ListBuilder<object> derivedAttributes)
RuntimeType attributeType, bool mustBeInheritable, ref RuntimeType.ListBuilder<object> derivedAttributes)
{
AttributeUsageAttribute? attributeUsageAttribute = null;

Expand Down Expand Up @@ -1595,7 +1595,7 @@ private static void VerifyPseudoCustomAttribute(RuntimeType pca)
#endregion

#region Internal Static
internal static void GetCustomAttributes(RuntimeType type, RuntimeType caType, ref ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeType type, RuntimeType caType, ref RuntimeType.ListBuilder<Attribute> pcas)
{
Debug.Assert(type is not null);
Debug.Assert(caType is not null);
Expand Down Expand Up @@ -1639,7 +1639,7 @@ internal static bool IsDefined(RuntimeType type, RuntimeType? caType)
return false;
}

internal static void GetCustomAttributes(RuntimeMethodInfo method, RuntimeType caType, ref ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeMethodInfo method, RuntimeType caType, ref RuntimeType.ListBuilder<Attribute> pcas)
{
Debug.Assert(method is not null);
Debug.Assert(caType is not null);
Expand Down Expand Up @@ -1679,7 +1679,7 @@ internal static bool IsDefined(RuntimeMethodInfo method, RuntimeType? caType)
return false;
}

internal static void GetCustomAttributes(RuntimeParameterInfo parameter, RuntimeType caType, ref ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeParameterInfo parameter, RuntimeType caType, ref RuntimeType.ListBuilder<Attribute> pcas)
{
Debug.Assert(parameter is not null);
Debug.Assert(caType is not null);
Expand Down Expand Up @@ -1735,7 +1735,7 @@ internal static bool IsDefined(RuntimeParameterInfo parameter, RuntimeType? caTy
return false;
}

internal static void GetCustomAttributes(RuntimeFieldInfo field, RuntimeType caType, ref ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeFieldInfo field, RuntimeType caType, ref RuntimeType.ListBuilder<Attribute> pcas)
{
Debug.Assert(field is not null);
Debug.Assert(caType is not null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,87 @@ internal enum MemberListType
HandleToInfo
}

// Helper to build lists of MemberInfos. Special cased to avoid allocations for lists of one element.
internal struct ListBuilder<T> where T : class
{
private T[]? _items;
private T _item;
private int _count;
private int _capacity;

public ListBuilder(int capacity)
{
_items = null;
_item = null!;
_count = 0;
_capacity = capacity;
}

public T this[int index]
{
get
{
Debug.Assert(index < Count);
return (_items != null) ? _items[index] : _item;
}
}

public T[] ToArray()
{
if (_count == 0)
return Array.Empty<T>();
if (_count == 1)
return new T[1] { _item };

Array.Resize(ref _items, _count);
_capacity = _count;
return _items!;
}

public void CopyTo(object[] array, int index)
{
if (_count == 0)
return;

if (_count == 1)
{
array[index] = _item;
return;
}

Array.Copy(_items!, 0, array, index, _count);
}

public int Count => _count;

public void Add(T item)
{
if (_count == 0)
{
_item = item;
}
else
{
if (_count == 1)
{
if (_capacity < 2)
_capacity = 4;
_items = new T[_capacity];
_items[0] = _item;
}
else if (_capacity == _count)
{
int newCapacity = 2 * _capacity;
Array.Resize(ref _items, newCapacity);
_capacity = newCapacity;
}

_items![_count] = item;
}
_count++;
}
}

internal sealed class RuntimeTypeCache
{
private const int MAXNAMELEN = 1024;
Expand Down Expand Up @@ -2745,7 +2826,7 @@ public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(Dyn
}

// All the methods have the exact same name and sig so return the most derived one.
return System.DefaultBinder.FindMostDerivedNewSlotMeth(candidates.AsSpan());
return System.DefaultBinder.FindMostDerivedNewSlotMeth(candidates.ToArray(), candidates.Count) as MethodInfo;
}
}

Expand Down Expand Up @@ -2774,7 +2855,7 @@ public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(Dyn
}

if ((bindingAttr & BindingFlags.ExactBinding) != 0)
return System.DefaultBinder.ExactBinding(candidates.AsSpan(), types);
return System.DefaultBinder.ExactBinding(candidates.ToArray(), types) as ConstructorInfo;

binder ??= DefaultBinder;
return binder.SelectMethod(bindingAttr, candidates.ToArray(), types, modifiers) as ConstructorInfo;
Expand Down Expand Up @@ -2812,7 +2893,7 @@ public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(Dyn
}

if ((bindingAttr & BindingFlags.ExactBinding) != 0)
return System.DefaultBinder.ExactPropertyBinding(candidates.AsSpan(), returnType, types);
return System.DefaultBinder.ExactPropertyBinding(candidates.ToArray(), returnType, types);

binder ??= DefaultBinder;
return binder.SelectProperty(bindingAttr, candidates.ToArray(), returnType, types, modifiers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@
<Compile Include="System\Reflection\Runtime\General\Helpers.cs" />
<Compile Include="System\Reflection\Runtime\General\IRuntimeMemberInfoWithNoMetadataDefinition.cs" />
<Compile Include="System\Reflection\Runtime\General\LegacyCustomAttributeApis.cs" />
<Compile Include="System\Reflection\Runtime\General\ListBuilder.cs" />
<Compile Include="System\Reflection\Runtime\General\MetadataReaderExtensions.cs" />
<Compile Include="System\Reflection\Runtime\General\MetadataReaderExtensions.NativeFormat.cs" />
<Compile Include="System\Reflection\Runtime\General\NamespaceChain.cs" />
Expand Down
Loading

0 comments on commit 0fae364

Please sign in to comment.