Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid a few array allocations with DefaultBinder #93115

Merged
merged 5 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
RuntimeType.ListBuilder<Attribute> pcas = default;
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);
RuntimeType.ListBuilder<Attribute> pcas = default;
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);
RuntimeType.ListBuilder<Attribute> pcas = default;
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);

RuntimeType.ListBuilder<Attribute> pcas = default;
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 RuntimeType.ListBuilder<Attribute> pseudoAttributes)
private static ReadOnlyCollection<CustomAttributeData> GetCombinedList(IList<CustomAttributeData> customAttributes, ref 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)!;

RuntimeType.ListBuilder<Attribute> pcas = default;
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;
}

RuntimeType.ListBuilder<object> result = default;
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)!;

RuntimeType.ListBuilder<Attribute> pcas = default;
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;
}

RuntimeType.ListBuilder<object> result = default;
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);

RuntimeType.ListBuilder<Attribute> pcas = default;
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);

RuntimeType.ListBuilder<Attribute> pcas = default;
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 @@ internal static bool IsAttributeDefined(RuntimeModule decoratedModule, int decor
{
Debug.Assert(attributeCtorToken == 0);

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

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

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

Expand All @@ -1156,11 +1156,11 @@ internal static bool IsAttributeDefined(RuntimeModule decoratedModule, int decor
"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 RuntimeType.ListBuilder<object> attributes,
ref 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
RuntimeType.ListBuilder<object> derivedAttributes)
ListBuilder<object> derivedAttributes)
{
CustomAttributeRecord[] car = RuntimeCustomAttributeData.GetCustomAttributeRecords(decoratedModule, decoratedMetadataToken);

Expand Down Expand Up @@ -1295,7 +1295,7 @@ internal static bool IsAttributeDefined(RuntimeModule decoratedModule, int decor
MetadataToken decoratedToken,
RuntimeType attributeFilterType,
bool mustBeInheritable,
ref RuntimeType.ListBuilder<object> derivedAttributes,
ref 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 RuntimeType.ListBuilder<object> derivedAttributes)
RuntimeType attributeType, bool mustBeInheritable, ref 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 RuntimeType.ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeType type, RuntimeType caType, ref 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 RuntimeType.ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeMethodInfo method, RuntimeType caType, ref 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 RuntimeType.ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeParameterInfo parameter, RuntimeType caType, ref 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 RuntimeType.ListBuilder<Attribute> pcas)
internal static void GetCustomAttributes(RuntimeFieldInfo field, RuntimeType caType, ref 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,87 +53,6 @@ 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 @@ -2826,7 +2745,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.ToArray(), candidates.Count) as MethodInfo;
return System.DefaultBinder.FindMostDerivedNewSlotMeth(candidates.AsSpan());
}
}

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

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

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

if ((bindingAttr & BindingFlags.ExactBinding) != 0)
return System.DefaultBinder.ExactPropertyBinding(candidates.ToArray(), returnType, types);
return System.DefaultBinder.ExactPropertyBinding(candidates.AsSpan(), 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 @@ -416,7 +416,6 @@
<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
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected sealed override ConstructorInfo GetConstructorImpl(BindingFlags bindin
}

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

binder ??= DefaultBinder;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\InvokeUtils.cs" Condition="'$(FeatureNativeAot)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\IReflect.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\IReflectableType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\ListBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\LocalVariableInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\ManifestResourceInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberFilter.cs" />
Expand Down Expand Up @@ -2719,4 +2720,4 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnaryPlusOperators.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnsignedNumber.cs" />
</ItemGroup>
</Project>
</Project>
Loading