From 09db3287fa5f0ae8ec920a769e4d779bb7015832 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 24 Jul 2024 21:42:26 +0800 Subject: [PATCH 01/10] Replace LowLevelListWithIList usage in reflection with List --- .../NativeFormat/NativeFormatCustomAttributeData.cs | 4 ++-- .../CustomAttributes/RuntimeCustomAttributeData.cs | 2 +- .../Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs index 10c49ffe177bb..24275045f67a2 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs @@ -116,7 +116,7 @@ internal sealed override IList GetConstructorArgum } Handle[] ctorTypeHandles = parameterTypeSignatureHandles.ToArray(); - LowLevelListWithIList customAttributeTypedArguments = new LowLevelListWithIList(); + List customAttributeTypedArguments = new List(_customAttribute.FixedArguments.Count); foreach (Handle fixedArgumentHandle in _customAttribute.FixedArguments) { Handle typeHandle = ctorTypeHandles[index]; @@ -155,7 +155,7 @@ internal sealed override IList GetConstructorArgum // internal sealed override IList GetNamedArguments(bool throwIfMissingMetadata) { - LowLevelListWithIList customAttributeNamedArguments = new LowLevelListWithIList(); + List customAttributeNamedArguments = new List(_customAttribute.NamedArguments.Count); foreach (NamedArgumentHandle namedArgumentHandle in _customAttribute.NamedArguments) { NamedArgument namedArgument = namedArgumentHandle.GetNamedArgument(_reader); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs index 12b0cde3b166f..f3af4e8d5d94a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs @@ -171,7 +171,7 @@ protected static CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument if (!argumentType.IsArray) throw new BadImageFormatException(); Type reportedElementType = argumentType.GetElementType()!; - LowLevelListWithIList elementTypedArguments = new LowLevelListWithIList(); + List elementTypedArguments = new List(); foreach (object elementValue in enumerableValue) { CustomAttributeTypedArgument elementTypedArgument = WrapInCustomAttributeTypedArgument(elementValue, reportedElementType); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs index 5383dc1f8ed68..0bf361277d3f6 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs @@ -266,7 +266,7 @@ internal abstract partial class RuntimeTypeInfo { #region Lookup Methods MethodInfo[] semiFinalists = (MethodInfo[])GetMember(name, MemberTypes.Method, bindingFlags); - LowLevelListWithIList? results = null; + List? results = null; for (int i = 0; i < semiFinalists.Length; i++) { @@ -284,7 +284,7 @@ internal abstract partial class RuntimeTypeInfo { if (results == null) { - results = new LowLevelListWithIList(semiFinalists.Length); + results = new List(semiFinalists.Length); results.Add(finalist); } @@ -309,7 +309,7 @@ internal abstract partial class RuntimeTypeInfo { #region Lookup Property PropertyInfo[] semiFinalists = (PropertyInfo[])GetMember(name, MemberTypes.Property, bindingFlags); - LowLevelListWithIList? results = null; + List? results = null; for (int i = 0; i < semiFinalists.Length; i++) { @@ -342,7 +342,7 @@ internal abstract partial class RuntimeTypeInfo { if (results == null) { - results = new LowLevelListWithIList(semiFinalists.Length); + results = new List(semiFinalists.Length); results.Add(finalist); } From ebce330ca9c1cace1e2a7150e6937ccc9b063a37 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 24 Jul 2024 21:50:46 +0800 Subject: [PATCH 02/10] Delete LowLevelListWithIList type --- .../Collections/Generic/LowLevelList.cs | 114 ------------------ 1 file changed, 114 deletions(-) diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs index a6e5e3a3fe975..a236b4a4f458d 100644 --- a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs +++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs @@ -31,7 +31,6 @@ namespace System.Collections.Generic // LowLevelList with no interface implementation minimizes both code and data size. // Data size is smaller because there will be minimal virtual function table. // Code size is smaller because only functions called will be in the binary. - // Use LowLevelListWithIList for IList support [DebuggerDisplay("Count = {Count}")] #if TYPE_LOADER_IMPLEMENTATION [System.Runtime.CompilerServices.ForceDictionaryLookups] @@ -435,117 +434,4 @@ public T[] ToArray() } #endif } - -#if !TYPE_LOADER_IMPLEMENTATION - // LowLevelList with full IList implementation - internal sealed class LowLevelListWithIList : LowLevelList, IList - { - public LowLevelListWithIList() - { - } - - public LowLevelListWithIList(int capacity) - : base(capacity) - { - } - - public LowLevelListWithIList(IEnumerable collection) - : base(collection) - { - } - - // Is this List read-only? - bool ICollection.IsReadOnly - { - get { return false; } - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return new Enumerator(this); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return new Enumerator(this); - } - - private struct Enumerator : IEnumerator, System.Collections.IEnumerator - { - private LowLevelListWithIList _list; - private int _index; - private int _version; - private T? _current; - - internal Enumerator(LowLevelListWithIList list) - { - _list = list; - _index = 0; - _version = list._version; - _current = default(T); - } - - public void Dispose() - { - } - - public bool MoveNext() - { - LowLevelListWithIList localList = _list; - - if (_version == localList._version && ((uint)_index < (uint)localList._size)) - { - _current = localList._items[_index]; - _index++; - return true; - } - return MoveNextRare(); - } - - private bool MoveNextRare() - { - if (_version != _list._version) - { - throw new InvalidOperationException(); - } - - _index = _list._size + 1; - _current = default(T); - return false; - } - - public T Current - { - get - { - return _current!; - } - } - - object? System.Collections.IEnumerator.Current - { - get - { - if (_index == 0 || _index == _list._size + 1) - { - throw new InvalidOperationException(); - } - return Current; - } - } - - void System.Collections.IEnumerator.Reset() - { - if (_version != _list._version) - { - throw new InvalidOperationException(); - } - - _index = 0; - _current = default(T); - } - } - } -#endif // !TYPE_LOADER_IMPLEMENTATION } From 83718e15f74d5515f05d84264aebe251e0ad8030 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 24 Jul 2024 22:39:49 +0800 Subject: [PATCH 03/10] Remove never used members --- .../Collections/Generic/LowLevelList.cs | 201 ------------------ 1 file changed, 201 deletions(-) diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs index a236b4a4f458d..a8491cd06576f 100644 --- a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs +++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs @@ -197,64 +197,6 @@ private void EnsureCapacity(int min) } #if !TYPE_LOADER_IMPLEMENTATION - // Adds the elements of the given collection to the end of this list. If - // required, the capacity of the list is increased to twice the previous - // capacity or the new size, whichever is larger. - // - public void AddRange(IEnumerable collection) - { - - InsertRange(_size, collection); - } - - // Clears the contents of List. - public void Clear() - { - if (_size > 0) - { - Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references. - _size = 0; - } - _version++; - } - - // Contains returns true if the specified element is in the List. - // It does a linear, O(n) search. Equality is determined by calling - // item.Equals(). - // - public bool Contains(T item) - { - if ((object?)item == null) - { - for (int i = 0; i < _size; i++) - if ((object?)_items[i] == null) - return true; - return false; - } - else - { - int index = IndexOf(item); - if (index >= 0) - return true; - return false; - } - } - - - // Copies a section of this list to the given array at the given index. - // - // The method uses the Array.Copy method to copy the elements. - // - public void CopyTo(int index, T[] array, int arrayIndex, int count) - { - if (_size - index < count) - { - throw new ArgumentException(); - } - - // Delegate rest of error checking to Array.Copy. - Array.Copy(_items, index, array, arrayIndex, count); - } public void CopyTo(T[] array, int arrayIndex) { @@ -262,35 +204,6 @@ public void CopyTo(T[] array, int arrayIndex) Array.Copy(_items, 0, array, arrayIndex, _size); } - // Returns the index of the first occurrence of a given value in a range of - // this list. The list is searched forwards from beginning to end. - // The elements of the list are compared to the given value using the - // Object.Equals method. - // - // This method uses the Array.IndexOf method to perform the - // search. - // - public int IndexOf(T item) - { - return Array.IndexOf(_items, item, 0, _size); - } - - - // Returns the index of the first occurrence of a given value in a range of - // this list. The list is searched forwards, starting at index - // index and ending at count number of elements. The - // elements of the list are compared to the given value using the - // Object.Equals method. - // - // This method uses the Array.IndexOf method to perform the - // search. - // - public int IndexOf(T item, int index) - { - ArgumentOutOfRangeException.ThrowIfGreaterThan(index, _size); - return Array.IndexOf(_items, item, index, _size - index); - } - // Inserts an element into this list at a given index. The size of the list // is increased by one. If required, the capacity of the list is doubled // before inserting the new element. @@ -310,120 +223,6 @@ public void Insert(int index, T item) _version++; } - // Inserts the elements of the given collection at a given index. If - // required, the capacity of the list is increased to twice the previous - // capacity or the new size, whichever is larger. Ranges may be added - // to the end of the list by setting index to the List's size. - // - public void InsertRange(int index, IEnumerable collection) - { - ArgumentNullException.ThrowIfNull(collection); - ArgumentOutOfRangeException.ThrowIfGreaterThan((uint)index, (uint)_size, nameof(index)); - - ICollection? c = collection as ICollection; - if (c != null) - { // if collection is ICollection - int count = c.Count; - if (count > 0) - { - EnsureCapacity(_size + count); - if (index < _size) - { - Array.Copy(_items, index, _items, index + count, _size - index); - } - - // If we're inserting a List into itself, we want to be able to deal with that. - if (this == c) - { - // Copy first part of _items to insert location - Array.Copy(_items, 0, _items, index, index); - // Copy last part of _items back to inserted location - Array.Copy(_items, index + count, _items, index * 2, _size - index); - } - else - { - T[] itemsToInsert = new T[count]; - c.CopyTo(itemsToInsert, 0); - Array.Copy(itemsToInsert, 0, _items, index, count); - } - _size += count; - } - } - else - { - using (IEnumerator en = collection.GetEnumerator()) - { - while (en.MoveNext()) - { - Insert(index++, en.Current); - } - } - } - _version++; - } - - // Removes the element at the given index. The size of the list is - // decreased by one. - // - public bool Remove(T item) - { - int index = IndexOf(item); - if (index >= 0) - { - RemoveAt(index); - return true; - } - - return false; - } - - // This method removes all items which matches the predicate. - // The complexity is O(n). - public int RemoveAll(Predicate match) - { - ArgumentNullException.ThrowIfNull(match); - - int freeIndex = 0; // the first free slot in items array - - // Find the first item which needs to be removed. - while (freeIndex < _size && !match(_items[freeIndex]!)) freeIndex++; - if (freeIndex >= _size) return 0; - - int current = freeIndex + 1; - while (current < _size) - { - // Find the first item which needs to be kept. - while (current < _size && match(_items[current]!)) current++; - - if (current < _size) - { - // copy item to the free slot. - _items[freeIndex++] = _items[current++]; - } - } - - Array.Clear(_items, freeIndex, _size - freeIndex); - int result = _size - freeIndex; - _size = freeIndex; - _version++; - return result; - } - - // Removes the element at the given index. The size of the list is - // decreased by one. - // - public void RemoveAt(int index) - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)index, (uint)_size, nameof(index)); - _size--; - if (index < _size) - { - Array.Copy(_items, index + 1, _items, index, _size - index); - } - _items[_size] = default!; - _version++; - } - // ToArray returns a new Object array containing the contents of the List. // This requires copying the List, which is an O(n) operation. public T[] ToArray() From 4c80f0bf3f7d3cca15597a275c5d55147b63bf27 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 24 Jul 2024 22:51:19 +0800 Subject: [PATCH 04/10] Replace CopyTo with ArrayBuilder --- .../Collections/Generic/LowLevelList.cs | 6 ----- .../System/Reflection/Attribute.NativeAot.cs | 19 +++++++++------ .../Reflection/Runtime/General/Helpers.cs | 24 +++++++++++-------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs index a8491cd06576f..dacd015f73321 100644 --- a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs +++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs @@ -198,12 +198,6 @@ private void EnsureCapacity(int min) #if !TYPE_LOADER_IMPLEMENTATION - public void CopyTo(T[] array, int arrayIndex) - { - // Delegate rest of error checking to Array.Copy. - Array.Copy(_items, 0, array, arrayIndex, _size); - } - // Inserts an element into this list at a given index. The size of the list // is increased by one. If required, the capacity of the list is doubled // before inserting the new element. diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs index a619095037b5c..0e7b0652d892c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs @@ -135,18 +135,23 @@ private static Attribute OneOrNull(IEnumerable results) Justification = "Arrays of reference types are safe to create.")] private static Attribute[] Instantiate(IEnumerable cads, Type actualElementType) { - LowLevelList attributes = new LowLevelList(); + ArrayBuilder attributes = default; foreach (CustomAttributeData cad in cads) { Attribute instantiatedAttribute = cad.Instantiate(); attributes.Add(instantiatedAttribute); } - int count = attributes.Count; - Attribute[] result = actualElementType.ContainsGenericParameters - ? new Attribute[count] - : (Attribute[])Array.CreateInstance(actualElementType, count); - attributes.CopyTo(result, 0); - return result; + + if (actualElementType.ContainsGenericParameters) + { + Attribute[] result = (Attribute[])Array.CreateInstance(actualElementType, attributes.Count); + attributes.AsSpan(0).CopyTo(result); + return result; + } + else + { + return attributes.ToArray(); + } } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs index abe62427fb1dd..1ae27fdb25046 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs @@ -151,22 +151,26 @@ public static BinderBundle ToBinderBundle(this Binder binder, BindingFlags invok Justification = "Array.CreateInstance is only used with reference types here and is therefore safe.")] public static object[] InstantiateAsArray(this IEnumerable cads, Type actualElementType) { - LowLevelList attributes = new LowLevelList(); + ArrayBuilder attributes = default; foreach (CustomAttributeData cad in cads) { object instantiatedAttribute = cad.Instantiate(); attributes.Add(instantiatedAttribute); } - // This is here for desktop compatibility. ICustomAttribute.GetCustomAttributes() normally returns an array of the - // exact attribute type requested except in two cases: when the passed in type is an open type and when - // it is a value type. In these two cases, it returns an array of type Object[]. - bool useObjectArray = actualElementType.ContainsGenericParameters || actualElementType.IsValueType; - int count = attributes.Count; - object[] result = useObjectArray ? new object[count] : (object[])Array.CreateInstance(actualElementType, count); - - attributes.CopyTo(result, 0); - return result; + if (actualElementType.ContainsGenericParameters || actualElementType.IsValueType) + { + // This is here for desktop compatibility. ICustomAttribute.GetCustomAttributes() normally returns an array of the + // exact attribute type requested except in two cases: when the passed in type is an open type and when + // it is a value type. In these two cases, it returns an array of type Object[]. + return attributes.ToArray(); + } + else + { + object[] result = (object[])Array.CreateInstance(actualElementType, attributes.Count); + attributes.AsSpan(0).CopyTo(result); + return result; + } } private static object? GetRawDefaultValue(IEnumerable customAttributes) From 802a46beca1583e47291890be170f684a94e2084 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 24 Jul 2024 23:11:01 +0800 Subject: [PATCH 05/10] Replace ToArray with ArrayBuilder --- .../Collections/Generic/LowLevelList.cs | 31 ------------------- .../MetadataReaderExtensions.NativeFormat.cs | 5 +-- .../General/TypeResolver.NativeFormat.cs | 2 +- ...veFormatRuntimeGenericParameterTypeInfo.cs | 2 +- .../NativeFormatRuntimeNamedTypeInfo.cs | 4 +-- .../RuntimeGenericParameterTypeInfo.cs | 2 +- ...EnvironmentImplementation.MappingTables.cs | 2 +- .../LowLevelEnumerable.ToArray.cs | 6 ++-- .../Collections/Generic/ArrayBuilder.cs | 5 +++ 9 files changed, 17 insertions(+), 42 deletions(-) diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs index dacd015f73321..bd3a854f39a64 100644 --- a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs +++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs @@ -195,36 +195,5 @@ private void EnsureCapacity(int min) Capacity = newCapacity; } } - -#if !TYPE_LOADER_IMPLEMENTATION - - // Inserts an element into this list at a given index. The size of the list - // is increased by one. If required, the capacity of the list is doubled - // before inserting the new element. - // - public void Insert(int index, T item) - { - // Note that insertions at the end are legal. - ArgumentOutOfRangeException.ThrowIfGreaterThan((uint)index, (uint)_size, nameof(index)); - - if (_size == _items.Length) EnsureCapacity(_size + 1); - if (index < _size) - { - Array.Copy(_items, index, _items, index + 1, _size - index); - } - _items[index] = item; - _size++; - _version++; - } - - // ToArray returns a new Object array containing the contents of the List. - // This requires copying the List, which is an O(n) operation. - public T[] ToArray() - { - T[] array = new T[_size]; - Array.Copy(_items, 0, array, 0, _size); - return array; - } -#endif } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs index f9f89d7343575..5f261f077790d 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs @@ -79,20 +79,21 @@ internal static Type[] GetCustomModifiers(this Handle handle, MetadataReader rea if (handleType != HandleType.ModifiedType) return Array.Empty(); - LowLevelList customModifiers = new LowLevelList(); + ArrayBuilder customModifiers = default; do { NativeFormatModifiedType modifiedType = handle.ToModifiedTypeHandle(reader).GetModifiedType(reader); if (optional == modifiedType.IsOptional) { Type customModifier = modifiedType.ModifierType.Resolve(reader, typeContext).ToType(); - customModifiers.Insert(0, customModifier); + customModifiers.Add(customModifier); } handle = modifiedType.Type; handleType = handle.HandleType; } while (handleType == HandleType.ModifiedType); + customModifiers.AsSpan(0).Reverse(); return customModifiers.ToArray(); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs index 44be913b0195c..3aed59328d502 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs @@ -138,7 +138,7 @@ internal static RuntimeTypeInfo ResolveTypeDefinition(this TypeDefinitionHandle RuntimeTypeInfo? genericTypeDefinition = sig.GenericType.TryResolve(reader, typeContext, ref exception); if (genericTypeDefinition == null) return null; - LowLevelList genericTypeArguments = new LowLevelList(); + ArrayBuilder genericTypeArguments = new ArrayBuilder(sig.GenericTypeArguments.Count); foreach (Handle genericTypeArgumentHandle in sig.GenericTypeArguments) { RuntimeTypeInfo? genericTypeArgument = genericTypeArgumentHandle.TryResolve(reader, typeContext, ref exception); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs index a64e338004eae..c3090aa47eb10 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs @@ -73,7 +73,7 @@ protected sealed override QTypeDefRefOrSpec[] Constraints get { MetadataReader reader = Reader; - LowLevelList constraints = new LowLevelList(); + ArrayBuilder constraints = new ArrayBuilder(_genericParameter.Constraints.Count); foreach (Handle constraintHandle in _genericParameter.Constraints) { // We're skipping custom modifiers here because Roslyn generates diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs index 23c0aab5638c4..65f2c3597ecc2 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs @@ -199,7 +199,7 @@ internal sealed override RuntimeTypeInfo[] RuntimeGenericTypeParameters { get { - LowLevelList genericTypeParameters = new LowLevelList(); + ArrayBuilder genericTypeParameters = new ArrayBuilder(_typeDefinition.GenericParameters.Count); foreach (GenericParameterHandle genericParameterHandle in _typeDefinition.GenericParameters) { @@ -233,7 +233,7 @@ internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImpleme { get { - LowLevelList directlyImplementedInterfaces = new LowLevelList(); + ArrayBuilder directlyImplementedInterfaces = new ArrayBuilder(_typeDefinition.Interfaces.Count); foreach (Handle ifcHandle in _typeDefinition.Interfaces) directlyImplementedInterfaces.Add(new QTypeDefRefOrSpec(_reader, ifcHandle)); return directlyImplementedInterfaces.ToArray(); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs index 3462bde38cf7a..478193a4400c9 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs @@ -152,8 +152,8 @@ internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImpleme { get { - LowLevelList result = new LowLevelList(); QTypeDefRefOrSpec[] constraints = Constraints; + ArrayBuilder result = new ArrayBuilder(constraints.Length); RuntimeTypeInfo[] constraintInfos = ConstraintInfos; for (int i = 0; i < constraints.Length; i++) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs index 34319199651d9..fd9fba5b7d12e 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs @@ -591,7 +591,7 @@ private static FunctionPointersToOffsets ComputeLdftnReverseLookup_InvokeMap(Nat NativeParser invokeMapParser = new NativeParser(invokeMapReader, 0); NativeHashtable invokeHashtable = new NativeHashtable(invokeMapParser); - LowLevelList functionPointers = new LowLevelList(); + ArrayBuilder functionPointers = default; var lookup = invokeHashtable.EnumerateAllEntries(); NativeParser entryParser; diff --git a/src/coreclr/tools/Common/Internal/LowLevelLinq/LowLevelEnumerable.ToArray.cs b/src/coreclr/tools/Common/Internal/LowLevelLinq/LowLevelEnumerable.ToArray.cs index 6d28c01316adc..e9bb5c90898f0 100644 --- a/src/coreclr/tools/Common/Internal/LowLevelLinq/LowLevelEnumerable.ToArray.cs +++ b/src/coreclr/tools/Common/Internal/LowLevelLinq/LowLevelEnumerable.ToArray.cs @@ -13,12 +13,12 @@ public static T[] ToArray(this IEnumerable values) { Debug.Assert(values != null); - LowLevelList list = new LowLevelList(); + ArrayBuilder arrayBuilder = default; foreach (T value in values) { - list.Add(value); + arrayBuilder.Add(value); } - return list.ToArray(); + return arrayBuilder.ToArray(); } } } diff --git a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs index 0005f54747827..a55f28f44738a 100644 --- a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs +++ b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs @@ -15,6 +15,11 @@ internal struct ArrayBuilder private T[] _items; private int _count; + public ArrayBuilder(int capacity) + { + _items = new T[capacity]; + } + public T[] ToArray() { if (_items == null) From 9242d5f83a3a8e8f03d1b639e406e74904a1e587 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 25 Jul 2024 00:47:13 +0800 Subject: [PATCH 06/10] Fix inverted condition --- .../src/System/Reflection/Attribute.NativeAot.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs index 0e7b0652d892c..144be0e3b7181 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs @@ -144,13 +144,13 @@ private static Attribute[] Instantiate(IEnumerable cads, Ty if (actualElementType.ContainsGenericParameters) { - Attribute[] result = (Attribute[])Array.CreateInstance(actualElementType, attributes.Count); - attributes.AsSpan(0).CopyTo(result); - return result; + return attributes.ToArray(); } else { - return attributes.ToArray(); + Attribute[] result = (Attribute[])Array.CreateInstance(actualElementType, attributes.Count); + attributes.AsSpan(0).CopyTo(result); + return result; } } } From b96af645163a1994bd2201867592f9110f462533 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 25 Jul 2024 00:57:55 +0800 Subject: [PATCH 07/10] Fix CopyTo with covariant destination --- .../src/System/Reflection/Attribute.NativeAot.cs | 2 +- .../src/System/Reflection/Runtime/General/Helpers.cs | 2 +- .../Common/System/Collections/Generic/ArrayBuilder.cs | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs index 144be0e3b7181..b68c2234d88fa 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs @@ -149,7 +149,7 @@ private static Attribute[] Instantiate(IEnumerable cads, Ty else { Attribute[] result = (Attribute[])Array.CreateInstance(actualElementType, attributes.Count); - attributes.AsSpan(0).CopyTo(result); + attributes.CopyTo(result); return result; } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs index 1ae27fdb25046..b6d019046c388 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs @@ -168,7 +168,7 @@ public static object[] InstantiateAsArray(this IEnumerable else { object[] result = (object[])Array.CreateInstance(actualElementType, attributes.Count); - attributes.AsSpan(0).CopyTo(result); + attributes.CopyTo(result); return result; } } diff --git a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs index a55f28f44738a..87a2024aad8a2 100644 --- a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs +++ b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs @@ -29,6 +29,15 @@ public T[] ToArray() return _items; } + public void CopyTo(T[] destination) + { + if (_items != null) + { + // Use Array.Copy instead of Span.CopyTo to handle covariant destination + Array.Copy(_items, destination, _count); + } + } + public void Add(T item) { if (_items == null || _count == _items.Length) From 25bb81bddce341723ce44e57801ee1d66531e948 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 25 Jul 2024 13:12:37 +0800 Subject: [PATCH 08/10] Update semantic of AsSpan --- .../tools/Common/System/Collections/Generic/ArrayBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs index 87a2024aad8a2..3859ad0557cd3 100644 --- a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs +++ b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs @@ -46,7 +46,7 @@ public void Add(T item) } #if NET - public readonly Span AsSpan(int start) => _items.AsSpan(start); + public readonly Span AsSpan(int start) => _items.AsSpan(start, _count); public Span AppendSpan(int length) { From 7f5e07dde8357cea52353b9af870fa6e4f5980ae Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 25 Jul 2024 13:23:01 +0800 Subject: [PATCH 09/10] Replace more List usage with ArratBuilder --- .../NativeFormatCustomAttributeData.cs | 8 +++---- .../RuntimeCustomAttributeData.cs | 4 ++-- .../TypeInfos/RuntimeTypeInfo.InvokeMember.cs | 22 +++++++------------ 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs index 24275045f67a2..e7a7202b0400c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs @@ -116,7 +116,7 @@ internal sealed override IList GetConstructorArgum } Handle[] ctorTypeHandles = parameterTypeSignatureHandles.ToArray(); - List customAttributeTypedArguments = new List(_customAttribute.FixedArguments.Count); + ArrayBuilder customAttributeTypedArguments = new ArrayBuilder(_customAttribute.FixedArguments.Count); foreach (Handle fixedArgumentHandle in _customAttribute.FixedArguments) { Handle typeHandle = ctorTypeHandles[index]; @@ -147,7 +147,7 @@ internal sealed override IList GetConstructorArgum index++; } - return customAttributeTypedArguments; + return customAttributeTypedArguments.ToArray(); } // @@ -155,7 +155,7 @@ internal sealed override IList GetConstructorArgum // internal sealed override IList GetNamedArguments(bool throwIfMissingMetadata) { - List customAttributeNamedArguments = new List(_customAttribute.NamedArguments.Count); + ArrayBuilder customAttributeNamedArguments = new ArrayBuilder(_customAttribute.NamedArguments.Count); foreach (NamedArgumentHandle namedArgumentHandle in _customAttribute.NamedArguments) { NamedArgument namedArgument = namedArgumentHandle.GetNamedArgument(_reader); @@ -185,7 +185,7 @@ internal sealed override IList GetNamedArguments(b customAttributeNamedArguments.Add(CreateCustomAttributeNamedArgument(this.AttributeType, memberName, isField, typedValue)); } - return customAttributeNamedArguments; + return customAttributeNamedArguments.ToArray(); } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs index f3af4e8d5d94a..12b6000851694 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs @@ -171,13 +171,13 @@ protected static CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument if (!argumentType.IsArray) throw new BadImageFormatException(); Type reportedElementType = argumentType.GetElementType()!; - List elementTypedArguments = new List(); + ArrayBuilder elementTypedArguments = default; foreach (object elementValue in enumerableValue) { CustomAttributeTypedArgument elementTypedArgument = WrapInCustomAttributeTypedArgument(elementValue, reportedElementType); elementTypedArguments.Add(elementTypedArgument); } - return new CustomAttributeTypedArgument(argumentType, new ReadOnlyCollection(elementTypedArguments)); + return new CustomAttributeTypedArgument(argumentType, new ReadOnlyCollection(elementTypedArguments.ToArray())); } else { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs index 0bf361277d3f6..7a8621c1bd1e5 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs @@ -266,7 +266,7 @@ internal abstract partial class RuntimeTypeInfo { #region Lookup Methods MethodInfo[] semiFinalists = (MethodInfo[])GetMember(name, MemberTypes.Method, bindingFlags); - List? results = null; + ArrayBuilder results = default; for (int i = 0; i < semiFinalists.Length; i++) { @@ -282,9 +282,8 @@ internal abstract partial class RuntimeTypeInfo } else { - if (results == null) + if (results.Count == 0) { - results = new List(semiFinalists.Length); results.Add(finalist); } @@ -292,11 +291,9 @@ internal abstract partial class RuntimeTypeInfo } } - if (results != null) + if (results.Count > 0) { - Debug.Assert(results.Count > 1); - finalists = new MethodInfo[results.Count]; - results.CopyTo(finalists, 0); + finalists = results.ToArray(); } #endregion } @@ -309,7 +306,7 @@ internal abstract partial class RuntimeTypeInfo { #region Lookup Property PropertyInfo[] semiFinalists = (PropertyInfo[])GetMember(name, MemberTypes.Property, bindingFlags); - List? results = null; + ArrayBuilder results = default; for (int i = 0; i < semiFinalists.Length; i++) { @@ -340,9 +337,8 @@ internal abstract partial class RuntimeTypeInfo } else { - if (results == null) + if (results.Count == 0) { - results = new List(semiFinalists.Length); results.Add(finalist); } @@ -350,11 +346,9 @@ internal abstract partial class RuntimeTypeInfo } } - if (results != null) + if (results.Count > 0) { - Debug.Assert(results.Count > 1); - finalists = new MethodInfo[results.Count]; - results.CopyTo(finalists, 0); + finalists = results.ToArray(); } #endregion } From e58c5a9da1247420ecd176545dba0dba3fa527f7 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 25 Jul 2024 15:28:38 +0800 Subject: [PATCH 10/10] Fix AsSpan --- .../Runtime/General/MetadataReaderExtensions.NativeFormat.cs | 2 +- .../tools/Common/System/Collections/Generic/ArrayBuilder.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs index 5f261f077790d..46ad09d02bf66 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs @@ -93,7 +93,7 @@ internal static Type[] GetCustomModifiers(this Handle handle, MetadataReader rea handleType = handle.HandleType; } while (handleType == HandleType.ModifiedType); - customModifiers.AsSpan(0).Reverse(); + customModifiers.AsSpan().Reverse(); return customModifiers.ToArray(); } diff --git a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs index 3859ad0557cd3..c947e2c762ff6 100644 --- a/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs +++ b/src/coreclr/tools/Common/System/Collections/Generic/ArrayBuilder.cs @@ -46,7 +46,9 @@ public void Add(T item) } #if NET - public readonly Span AsSpan(int start) => _items.AsSpan(start, _count); + public readonly Span AsSpan() => _items.AsSpan(0, _count); + + public readonly Span AsSpan(int start) => _items.AsSpan(start, _count - start); public Span AppendSpan(int length) {