diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelDictionary.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelDictionary.cs deleted file mode 100644 index a0fd2c6b7ba963..00000000000000 --- a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelDictionary.cs +++ /dev/null @@ -1,304 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace System.Collections.Generic -{ - /*============================================================ - ** - ** Class: LowLevelDictionary - ** - ** Private version of Dictionary<> for internal System.Private.CoreLib use. This - ** permits sharing more source between BCL and System.Private.CoreLib (as well as the - ** fact that Dictionary<> is just a useful class in general.) - ** - ** This does not strive to implement the full api surface area - ** (but any portion it does implement should match the real Dictionary<>'s - ** behavior.) - ** - ===========================================================*/ - internal class LowLevelDictionary where TKey : IEquatable - { - private const int DefaultSize = 17; - - public LowLevelDictionary() - : this(DefaultSize) - { - } - - public LowLevelDictionary(int capacity) - { - Clear(capacity); - } - - public int Count - { - get - { - return _numEntries; - } - } - - public TValue this[TKey key] - { - get - { - ArgumentNullException.ThrowIfNull(key); - - Entry entry = Find(key); - if (entry == null) - throw new KeyNotFoundException(); - return entry.m_value; - } - set - { - ArgumentNullException.ThrowIfNull(key); - - _version++; - Entry entry = Find(key); - if (entry != null) - entry.m_value = value; - else - UncheckedAdd(key, value); - } - } - - public bool TryGetValue(TKey key, out TValue? value) - { - ArgumentNullException.ThrowIfNull(key); - - value = default(TValue); - Entry entry = Find(key); - if (entry != null) - { - value = entry.m_value; - return true; - } - return false; - } - - public void Add(TKey key, TValue value) - { - ArgumentNullException.ThrowIfNull(key); - - Entry entry = Find(key); - if (entry != null) - throw new ArgumentException(SR.Format(SR.Argument_AddingDuplicate, key)); - _version++; - UncheckedAdd(key, value); - } - - public void Clear(int capacity = DefaultSize) - { - _version++; - _buckets = new Entry[capacity]; - _numEntries = 0; - } - - public bool Remove(TKey key) - { - ArgumentNullException.ThrowIfNull(key); - - int bucket = GetBucket(key); - Entry? prev = null; - Entry? entry = _buckets[bucket]; - while (entry != null) - { - if (key.Equals(entry.m_key)) - { - if (prev == null) - { - _buckets[bucket] = entry.m_next; - } - else - { - prev.m_next = entry.m_next; - } - _version++; - _numEntries--; - return true; - } - - prev = entry; - entry = entry.m_next; - } - return false; - } - - internal TValue LookupOrAdd(TKey key, TValue value) - { - Entry entry = Find(key); - if (entry != null) - return entry.m_value; - UncheckedAdd(key, value); - return value; - } - - private Entry Find(TKey key) - { - int bucket = GetBucket(key); - Entry? entry = _buckets[bucket]; - while (entry != null) - { - if (key.Equals(entry.m_key)) - return entry; - - entry = entry.m_next; - } - return null; - } - - private Entry UncheckedAdd(TKey key, TValue value) - { - Entry entry = new Entry(); - entry.m_key = key; - entry.m_value = value; - - int bucket = GetBucket(key); - entry.m_next = _buckets[bucket]; - _buckets[bucket] = entry; - - _numEntries++; - if (_numEntries > (_buckets.Length * 2)) - ExpandBuckets(); - - return entry; - } - - - private void ExpandBuckets() - { - try - { - int newNumBuckets = _buckets.Length * 2 + 1; - Entry[] newBuckets = new Entry[newNumBuckets]; - for (int i = 0; i < _buckets.Length; i++) - { - Entry? entry = _buckets[i]; - while (entry != null) - { - Entry? nextEntry = entry.m_next; - - int bucket = GetBucket(entry.m_key, newNumBuckets); - entry.m_next = newBuckets[bucket]; - newBuckets[bucket] = entry; - - entry = nextEntry; - } - } - _buckets = newBuckets; - } - catch (OutOfMemoryException) - { - } - } - - private int GetBucket(TKey key, int numBuckets = 0) - { - int h = key.GetHashCode(); - h &= 0x7fffffff; - return (h % (numBuckets == 0 ? _buckets.Length : numBuckets)); - } - - private sealed class Entry - { - public TKey m_key; - public TValue m_value; - public Entry? m_next; - } - - private Entry?[] _buckets; - private int _numEntries; - private int _version; - - protected sealed class LowLevelDictEnumerator : IEnumerator> - { - public LowLevelDictEnumerator(LowLevelDictionary dict) - { - _dict = dict; - _version = _dict._version; - Entry[] entries = new Entry[_dict._numEntries]; - int dst = 0; - for (int bucket = 0; bucket < _dict._buckets.Length; bucket++) - { - Entry? entry = _dict._buckets[bucket]; - while (entry != null) - { - entries[dst++] = entry; - entry = entry.m_next; - } - } - _entries = entries; - Reset(); - } - - public KeyValuePair Current - { - get - { - if (_version != _dict._version) - throw new InvalidOperationException("InvalidOperation_EnumFailedVersion"); - if (_curPosition == -1 || _curPosition == _entries.Length) - throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen"); - Entry entry = _entries[_curPosition]; - return new KeyValuePair(entry.m_key, entry.m_value); - } - } - - public void Dispose() - { - } - - public bool MoveNext() - { - if (_version != _dict._version) - throw new InvalidOperationException("InvalidOperation_EnumFailedVersion"); - if (_curPosition != _entries.Length) - _curPosition++; - bool anyMore = (_curPosition != _entries.Length); - return anyMore; - } - - object IEnumerator.Current - { - get - { - KeyValuePair kv = Current; - return kv; - } - } - - public void Reset() - { - if (_version != _dict._version) - throw new InvalidOperationException("InvalidOperation_EnumFailedVersion"); - _curPosition = -1; - } - - private LowLevelDictionary _dict; - private Entry[] _entries; - private int _curPosition; - private int _version; - } - } - - /// - /// LowLevelDictionary when enumeration is needed - /// - internal sealed class LowLevelDictionaryWithIEnumerable : LowLevelDictionary, IEnumerable> where TKey : IEquatable - { - public IEnumerator> GetEnumerator() - { - return new LowLevelDictEnumerator(this); - } - - IEnumerator IEnumerable.GetEnumerator() - { - IEnumerator> ie = GetEnumerator(); - return ie; - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs index 8249b4c58a32d6..3298263cf18f53 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs @@ -7,6 +7,7 @@ using System.Collections.ObjectModel; using System.Diagnostics; using System.Reflection; +using System.Runtime.InteropServices; //================================================================================================================== // Dependency note: @@ -133,14 +134,12 @@ private IEnumerable GetMatchingCustomAttributesIterator(E e // // - Cache the results of retrieving the usage attribute. // - LowLevelDictionary encounteredTypes = new LowLevelDictionary(11); + Dictionary encounteredTypes = new Dictionary(); for (int i = 0; i < immediateResults.Count; i++) { Type attributeType = immediateResults[i].AttributeType; - TypeUnificationKey attributeTypeKey = new TypeUnificationKey(attributeType); - if (!encounteredTypes.TryGetValue(attributeTypeKey, out _)) - encounteredTypes.Add(attributeTypeKey, null); + encounteredTypes.TryAdd(attributeType, null); } do @@ -150,20 +149,18 @@ private IEnumerable GetMatchingCustomAttributesIterator(E e Type attributeType = cad.AttributeType; if (!passesFilter(attributeType)) continue; - AttributeUsageAttribute? usage; - TypeUnificationKey attributeTypeKey = new TypeUnificationKey(attributeType); - if (!encounteredTypes.TryGetValue(attributeTypeKey, out usage)) + + ref AttributeUsageAttribute? usage = ref CollectionsMarshal.GetValueRefOrAddDefault(encounteredTypes, attributeType, out bool exists); + if (!exists) { // Type was not encountered before. Only include it if it is inheritable. usage = GetAttributeUsage(attributeType); - encounteredTypes.Add(attributeTypeKey, usage); if (usage.Inherited) yield return cad; } else { usage ??= GetAttributeUsage(attributeType); - encounteredTypes[attributeTypeKey] = usage; // Type was encountered at a lower level. Only include it if its inheritable AND allowMultiple. if (usage.Inherited && usage.AllowMultiple) yield return cad; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs index c0bceb7963c8ad..5fae490b2f5860 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs @@ -17,42 +17,7 @@ public static class FunctionPointerOps private const int FatFunctionPointerOffset = 2; #endif - private struct GenericMethodDescriptorInfo : IEquatable - { - public override bool Equals(object? obj) - { - if (!(obj is GenericMethodDescriptorInfo)) - return false; - - return Equals((GenericMethodDescriptorInfo)obj); - } - - public bool Equals(GenericMethodDescriptorInfo other) - { - if (MethodFunctionPointer != other.MethodFunctionPointer) - return false; - - if (InstantiationArgument != other.InstantiationArgument) - return false; - - return true; - } - - public override int GetHashCode() - { - int a = InstantiationArgument.GetHashCode(); - int b = MethodFunctionPointer.GetHashCode(); - return (a ^ b) + (a << 11) - (b >> 13); - } - - public IntPtr MethodFunctionPointer; - public IntPtr InstantiationArgument; - } - - private static uint s_genericFunctionPointerNextIndex; - private const uint c_genericDictionaryChunkSize = 1024; - private static LowLevelList s_genericFunctionPointerCollection = new LowLevelList(); - private static LowLevelDictionary s_genericFunctionPointerDictionary = new LowLevelDictionary(); + private static Dictionary<(IntPtr MethodFunctionPointer, IntPtr InstantiationArgument), IntPtr> s_genericFunctionPointerDictionary = new Dictionary<(IntPtr, IntPtr), IntPtr>(); public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunctionPointer, IntPtr instantiationArgument) { @@ -63,44 +28,16 @@ public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunction lock (s_genericFunctionPointerDictionary) { - var key = new GenericMethodDescriptorInfo - { - MethodFunctionPointer = canonFunctionPointer, - InstantiationArgument = instantiationArgument - }; - - uint index = 0; - if (!s_genericFunctionPointerDictionary.TryGetValue(key, out index)) + ref IntPtr descriptor = ref CollectionsMarshal.GetValueRefOrAddDefault(s_genericFunctionPointerDictionary, (canonFunctionPointer, instantiationArgument), out bool exists); + if (!exists) { - // Capture new index value - index = s_genericFunctionPointerNextIndex; + descriptor = (IntPtr)NativeMemory.Alloc((uint)sizeof(GenericMethodDescriptor)); - int newChunkIndex = (int)(index / c_genericDictionaryChunkSize); - uint newSubChunkIndex = index % c_genericDictionaryChunkSize; - - // Generate new chunk if existing chunks are insufficient - if (s_genericFunctionPointerCollection.Count <= newChunkIndex) - { - Debug.Assert(newSubChunkIndex == 0); - - // New generic descriptors are allocated on the native heap and not tracked in the GC. - IntPtr pNewMem = (IntPtr)NativeMemory.Alloc(c_genericDictionaryChunkSize, (nuint)sizeof(GenericMethodDescriptor)); - s_genericFunctionPointerCollection.Add(pNewMem); - } - - ((GenericMethodDescriptor*)s_genericFunctionPointerCollection[newChunkIndex])[newSubChunkIndex] = + *(GenericMethodDescriptor*)descriptor = new GenericMethodDescriptor(canonFunctionPointer, instantiationArgument); - - s_genericFunctionPointerDictionary.LookupOrAdd(key, index); - - // Now that we can no longer have failed, update the next index. - s_genericFunctionPointerNextIndex++; } - // Lookup within list - int chunkIndex = (int)(index / c_genericDictionaryChunkSize); - uint subChunkIndex = index % c_genericDictionaryChunkSize; - GenericMethodDescriptor* genericFunctionPointer = &((GenericMethodDescriptor*)s_genericFunctionPointerCollection[chunkIndex])[subChunkIndex]; + GenericMethodDescriptor* genericFunctionPointer = (GenericMethodDescriptor*)descriptor; Debug.Assert(canonFunctionPointer == genericFunctionPointer->MethodFunctionPointer); Debug.Assert(instantiationArgument == genericFunctionPointer->InstantiationArgument); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs index e3ee1f3eedb79c..f3274f81b2964d 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs @@ -224,18 +224,18 @@ public override bool Equals(object? obj) return ((OpenMethodResolver)obj).Equals(this); } - private static LowLevelDictionary s_internedResolverHash = new LowLevelDictionary(); + private static Dictionary s_internedResolverHash = new Dictionary(); public IntPtr ToIntPtr() { lock (s_internedResolverHash) { - IntPtr returnValue; - if (s_internedResolverHash.TryGetValue(this, out returnValue)) - return returnValue; - returnValue = (IntPtr)NativeMemory.Alloc((nuint)sizeof(OpenMethodResolver)); - *((OpenMethodResolver*)returnValue) = this; - s_internedResolverHash.Add(this, returnValue); + ref IntPtr returnValue = ref CollectionsMarshal.GetValueRefOrAddDefault(s_internedResolverHash, this, out bool exists); + if (!exists) + { + returnValue = (IntPtr)NativeMemory.Alloc((nuint)sizeof(OpenMethodResolver)); + *((OpenMethodResolver*)returnValue) = this; + } return returnValue; } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index f8f6e6374592c0..81b1da7b670553 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -234,7 +234,6 @@ - @@ -327,9 +326,6 @@ System\Collections\Generic\LowLevelList.cs - - System\Collections\Generic\LowLevelDictionary.cs - System\Collections\Concurrent\ConcurrentUnifier.cs diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs index 20dbd1206ef754..2b17ee83f6ce2e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs @@ -7,7 +7,6 @@ using System.Reflection.Runtime.TypeInfos; using Internal.Metadata.NativeFormat; -using Internal.Reflection.Core; namespace System.Reflection.Runtime.Assemblies.NativeFormat { @@ -15,9 +14,8 @@ internal partial class NativeFormatRuntimeAssembly { internal sealed override RuntimeTypeInfo GetTypeCoreCaseInsensitive(string fullName) { - LowLevelDictionary dict = CaseInsensitiveTypeDictionary; - QHandle qualifiedHandle; - if (!dict.TryGetValue(fullName.ToLowerInvariant(), out qualifiedHandle)) + Dictionary dict = CaseInsensitiveTypeDictionary; + if (!dict.TryGetValue(fullName, out QHandle qualifiedHandle)) { return null; } @@ -48,7 +46,7 @@ internal sealed override RuntimeTypeInfo GetTypeCoreCaseInsensitive(string fullN } } - private LowLevelDictionary CaseInsensitiveTypeDictionary + private Dictionary CaseInsensitiveTypeDictionary { get { @@ -56,7 +54,7 @@ private LowLevelDictionary CaseInsensitiveTypeDictionary } } - private LowLevelDictionary CreateCaseInsensitiveTypeDictionary() + private Dictionary CreateCaseInsensitiveTypeDictionary() { // // Collect all of the *non-nested* types and type-forwards. @@ -70,7 +68,7 @@ private LowLevelDictionary CreateCaseInsensitiveTypeDictionary( // same issue.) // - LowLevelDictionary dict = new LowLevelDictionary(); + Dictionary dict = new Dictionary(StringComparer.OrdinalIgnoreCase); MetadataReader reader = Scope.Reader; ScopeDefinition scopeDefinition = Scope.ScopeDefinition; @@ -87,25 +85,19 @@ private LowLevelDictionary CreateCaseInsensitiveTypeDictionary( foreach (TypeDefinitionHandle typeDefinitionHandle in namespaceDefinition.TypeDefinitions) { string fullName = ns + typeDefinitionHandle.GetTypeDefinition(reader).Name.GetString(reader).ToLowerInvariant(); - if (!dict.TryGetValue(fullName, out _)) - { - dict.Add(fullName, new QHandle(reader, typeDefinitionHandle)); - } + dict.TryAdd(fullName, new QHandle(reader, typeDefinitionHandle)); } foreach (TypeForwarderHandle typeForwarderHandle in namespaceDefinition.TypeForwarders) { string fullName = ns + typeForwarderHandle.GetTypeForwarder(reader).Name.GetString(reader).ToLowerInvariant(); - if (!dict.TryGetValue(fullName, out _)) - { - dict.Add(fullName, new QHandle(reader, typeForwarderHandle)); - } + dict.TryAdd(fullName, new QHandle(reader, typeForwarderHandle)); } } return dict; } - private volatile LowLevelDictionary _lazyCaseInsensitiveTypeDictionary; + private volatile Dictionary _lazyCaseInsensitiveTypeDictionary; } } 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 12b6000851694c..44b163a977cd99 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 @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace System.Reflection.Runtime.CustomAttributes @@ -166,13 +167,13 @@ protected static CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument } // Handle the array case - if (value is IEnumerable enumerableValue && !(value is string)) + if (value is Array arr) { if (!argumentType.IsArray) throw new BadImageFormatException(); Type reportedElementType = argumentType.GetElementType()!; ArrayBuilder elementTypedArguments = default; - foreach (object elementValue in enumerableValue) + foreach (object elementValue in arr) { CustomAttributeTypedArgument elementTypedArgument = WrapInCustomAttributeTypedArgument(elementValue, reportedElementType); elementTypedArguments.Add(elementTypedArgument); @@ -181,6 +182,7 @@ protected static CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument } else { + Debug.Assert(value is string or (not IEnumerable)); return new CustomAttributeTypedArgument(argumentType, value); } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypeUnificationKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypeUnificationKey.cs deleted file mode 100644 index 48f437c544ec6b..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypeUnificationKey.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// Implements System.Type -// - -using System; -using System.Diagnostics; - -namespace System -{ - // - // Type doesn't implement IEquatable which makes it impossible to use a key in our unification tables. - // This wrapper is here to compensate for that. - // - internal struct TypeUnificationKey : IEquatable - { - public TypeUnificationKey(Type type) - { - Debug.Assert(type != null); - Type = type; - } - - public override bool Equals(object? obj) - { - if (!(obj is TypeUnificationKey)) - return false; - return Equals((TypeUnificationKey)obj); - } - - public bool Equals(TypeUnificationKey other) - { - return Type.Equals(other.Type); - } - - public override int GetHashCode() - { - return Type.GetHashCode(); - } - - public Type Type { get; } - } -} diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj index 86fb64fa51852c..95d9031003a7de 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj @@ -1,4 +1,4 @@ - + @@ -59,9 +59,6 @@ System\Collections\Generic\LowLevelList.cs - - System\Collections\Generic\LowLevelDictionary.cs - System\Collections\Generic\ArrayBuilder.cs diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs index f4353f9db8f54b..8dd7dff87aee45 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs @@ -94,15 +94,15 @@ internal sealed class ModuleMap /// /// Map of module handles to indices within the Modules array. /// - public readonly LowLevelDictionary HandleToModuleIndex; + public readonly Dictionary HandleToModuleIndex; internal ModuleMap(ModuleInfo[] modules) { Modules = modules; - HandleToModuleIndex = new LowLevelDictionary(); + HandleToModuleIndex = new Dictionary(); for (int moduleIndex = 0; moduleIndex < Modules.Length; moduleIndex++) { - HandleToModuleIndex.Add(Modules[moduleIndex].Handle, moduleIndex); + HandleToModuleIndex.Add(Modules[moduleIndex].Handle.GetIntPtrUNSAFE(), moduleIndex); } } } @@ -159,7 +159,7 @@ public struct NativeFormatModuleInfoEnumerator /// Preferred module index in the array, -1 when none (in such case the array is enumerated /// in its natural order). /// - private int _preferredIndex; + private nint _preferredIndex; /// /// Enumeration step index initially set to -1 (so that the first MoveNext increments it to 0). @@ -184,7 +184,7 @@ internal NativeFormatModuleInfoEnumerator(ModuleMap moduleMap, TypeManagerHandle _currentModule = null; if (!preferredModuleHandle.IsNull && - !moduleMap.HandleToModuleIndex.TryGetValue(preferredModuleHandle, out _preferredIndex)) + !moduleMap.HandleToModuleIndex.TryGetValue(preferredModuleHandle.GetIntPtrUNSAFE(), out _preferredIndex)) { Environment.FailFast("Invalid module requested in enumeration: " + preferredModuleHandle.LowLevelToString()); } @@ -205,7 +205,7 @@ public bool MoveNext() } _iterationIndex++; - int moduleIndex = _iterationIndex; + nint moduleIndex = _iterationIndex; if (moduleIndex <= _preferredIndex) { // Transform the index so that the _preferredIndex is returned in first iteration @@ -292,7 +292,7 @@ internal ModuleList() public NativeFormatModuleInfo GetModuleInfoByHandle(TypeManagerHandle moduleHandle) { ModuleMap moduleMap = _loadedModuleMap; - return (NativeFormatModuleInfo)moduleMap.Modules[moduleMap.HandleToModuleIndex[moduleHandle]]; + return (NativeFormatModuleInfo)moduleMap.Modules[moduleMap.HandleToModuleIndex[moduleHandle.GetIntPtrUNSAFE()]]; } /// @@ -304,8 +304,7 @@ public NativeFormatModuleInfo GetModuleInfoByHandle(TypeManagerHandle moduleHand public bool TryGetModuleInfoByHandle(TypeManagerHandle moduleHandle, out ModuleInfo moduleInfo) { ModuleMap moduleMap = _loadedModuleMap; - int moduleIndex; - if (moduleMap.HandleToModuleIndex.TryGetValue(moduleHandle, out moduleIndex)) + if (moduleMap.HandleToModuleIndex.TryGetValue(moduleHandle.GetIntPtrUNSAFE(), out IntPtr moduleIndex)) { moduleInfo = moduleMap.Modules[moduleIndex]; return true; @@ -322,8 +321,7 @@ public bool TryGetModuleInfoByHandle(TypeManagerHandle moduleHandle, out ModuleI public MetadataReader GetMetadataReaderForModule(TypeManagerHandle moduleHandle) { ModuleMap moduleMap = _loadedModuleMap; - int moduleIndex; - if (moduleMap.HandleToModuleIndex.TryGetValue(moduleHandle, out moduleIndex)) + if (moduleMap.HandleToModuleIndex.TryGetValue(moduleHandle.GetIntPtrUNSAFE(), out IntPtr moduleIndex)) { NativeFormatModuleInfo moduleInfo = moduleMap.Modules[moduleIndex] as NativeFormatModuleInfo; if (moduleInfo != null) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericTypesLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericTypesLookup.cs index 0c9adf60c80337..2d83dc507c54de 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericTypesLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericTypesLookup.cs @@ -169,31 +169,8 @@ internal bool MatchGenericTypeEntry(GenericTypeEntry entry) } } - internal struct LazyDictionaryContext : IEquatable - { - public IntPtr _context; - public IntPtr _signature; - - public override bool Equals(object obj) - { - if (!(obj is LazyDictionaryContext)) - return false; - return Equals((LazyDictionaryContext)obj); - } - - public bool Equals(LazyDictionaryContext other) - { - return _context == other._context && _signature == other._signature; - } - - public override int GetHashCode() - { - return _context.GetHashCode() ^ _signature.GetHashCode(); - } - } - private DynamicGenericTypesHashtable _dynamicGenericTypes = new DynamicGenericTypesHashtable(); - private LowLevelDictionary _lazyGenericDictionaries = new LowLevelDictionary(); + private Dictionary<(IntPtr Context, IntPtr Signature), IntPtr> _lazyGenericDictionaries = new Dictionary<(IntPtr, IntPtr), IntPtr>(); // @@ -217,7 +194,7 @@ public bool TryLookupConstructedGenericTypeForComponents(RuntimeTypeHandle gener public bool TryLookupConstructedLazyDictionaryForContext(IntPtr context, IntPtr signature, out IntPtr dictionary) { Debug.Assert(_typeLoaderLock.IsHeldByCurrentThread); - return _lazyGenericDictionaries.TryGetValue(new LazyDictionaryContext { _context = context, _signature = signature }, out dictionary); + return _lazyGenericDictionaries.TryGetValue((context, signature), out dictionary); } #region Privates diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericsRegistration.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericsRegistration.cs index 72c65865ff2afe..c19e3365a40c8b 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericsRegistration.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericsRegistration.cs @@ -131,7 +131,7 @@ internal void RegisterDynamicGenericTypesAndMethods(DynamicGenericsRegistrationD public void RegisterConstructedLazyDictionaryForContext(IntPtr context, IntPtr signature, IntPtr dictionary) { Debug.Assert(_typeLoaderLock.IsHeldByCurrentThread); - _lazyGenericDictionaries.Add(new LazyDictionaryContext { _context = context, _signature = signature }, dictionary); + _lazyGenericDictionaries.Add((context, signature), dictionary); } } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs index f28b55e5b0d6dc..3cdbb51d058a19 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs @@ -4,12 +4,7 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Reflection.Runtime.General; -using System.Runtime; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; using Internal.Metadata.NativeFormat; using Internal.NativeFormat; @@ -24,34 +19,6 @@ namespace Internal.Runtime.TypeLoader public sealed partial class TypeLoaderEnvironment { #region Ldtoken Hashtables - private struct RuntimeFieldHandleKey : IEquatable - { - private RuntimeTypeHandle _declaringType; - private FieldHandle _handle; - - public RuntimeFieldHandleKey(RuntimeTypeHandle declaringType, FieldHandle fieldHandle) - { - _declaringType = declaringType; - _handle = fieldHandle; - } - - public override bool Equals(object obj) - { - if (obj is RuntimeFieldHandleKey other) - { - return Equals(other); - } - return false; - } - - public bool Equals(RuntimeFieldHandleKey other) - { - return other._declaringType.Equals(_declaringType) && other._handle.Equals(_handle); - } - - public override int GetHashCode() => _declaringType.GetHashCode() ^ _handle.GetHashCode(); - } - private struct RuntimeMethodHandleKey : IEquatable { private RuntimeTypeHandle _declaringType; @@ -105,8 +72,10 @@ public override int GetHashCode() : TypeHashingAlgorithms.ComputeGenericInstanceHashCode(_declaringType.GetHashCode(), _genericArgs)); } - private LowLevelDictionary _runtimeFieldHandles = new LowLevelDictionary(); - private LowLevelDictionary _runtimeMethodHandles = new LowLevelDictionary(); + // To minimize the generic instantiations of Dictionary in CoreLib, use the instantiation <(IntPtr, IntPtr), IntPtr> + // that's shared with other instances. + private Dictionary<(IntPtr DeclaringType, IntPtr FieldHandle), IntPtr> _runtimeFieldHandles = new Dictionary<(IntPtr, IntPtr), IntPtr>(); + private Dictionary _runtimeMethodHandles = new Dictionary(); #endregion @@ -118,21 +87,21 @@ public unsafe RuntimeFieldHandle GetRuntimeFieldHandleForComponents(RuntimeTypeH public unsafe RuntimeFieldHandle GetRuntimeFieldHandleForComponents(RuntimeTypeHandle declaringTypeHandle, FieldHandle handle) { - RuntimeFieldHandleKey key = new RuntimeFieldHandleKey(declaringTypeHandle, handle); + (IntPtr, IntPtr) key = (RuntimeTypeHandle.ToIntPtr(declaringTypeHandle), ((Handle)handle).AsInt()); lock (_runtimeFieldHandles) { - if (!_runtimeFieldHandles.TryGetValue(key, out RuntimeFieldHandle runtimeFieldHandle)) + if (!_runtimeFieldHandles.TryGetValue(key, out IntPtr runtimeFieldHandle)) { FieldHandleInfo* fieldData = (FieldHandleInfo*)MemoryHelpers.AllocateMemory(sizeof(FieldHandleInfo)); fieldData->DeclaringType = declaringTypeHandle; fieldData->Handle = handle; - runtimeFieldHandle = RuntimeFieldHandle.FromIntPtr((nint)fieldData); + runtimeFieldHandle = (nint)fieldData; _runtimeFieldHandles.Add(key, runtimeFieldHandle); } - return runtimeFieldHandle; + return RuntimeFieldHandle.FromIntPtr(runtimeFieldHandle); } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.StaticsLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.StaticsLookup.cs index 6d6ce9422f4837..a8009d48682033 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.StaticsLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.StaticsLookup.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Threading; using Internal.NativeFormat; @@ -18,8 +19,8 @@ public sealed partial class TypeLoaderEnvironment private Lock _threadStaticsLock = new Lock(useTrivialWaits: true); // Counter to keep track of generated offsets for TLS cells of dynamic types; - private LowLevelDictionary _maxThreadLocalIndex = new LowLevelDictionary(); - private LowLevelDictionary> _dynamicGenericsThreadStaticDescs = new LowLevelDictionary>(); + private Dictionary _maxThreadLocalIndex = new Dictionary(); + private Dictionary> _dynamicGenericsThreadStaticDescs = new Dictionary>(); // Various functions in static access need to create permanent pointers for use by thread static lookup. #region GC/Non-GC Statics @@ -142,7 +143,7 @@ public IntPtr TryGetThreadStaticFieldData(RuntimeTypeHandle runtimeTypeHandle) return IntPtr.Zero; } - public IntPtr GetThreadStaticGCDescForDynamicType(TypeManagerHandle typeManagerHandle, uint index) + public IntPtr GetThreadStaticGCDescForDynamicType(TypeManagerHandle typeManagerHandle, nint index) { using (_threadStaticsLock.EnterScope()) { @@ -152,12 +153,13 @@ public IntPtr GetThreadStaticGCDescForDynamicType(TypeManagerHandle typeManagerH public uint GetNextThreadStaticsOffsetValue(TypeManagerHandle typeManagerHandle) { - if (!_maxThreadLocalIndex.TryGetValue(typeManagerHandle.GetIntPtrUNSAFE(), out uint result)) - result = (uint)RuntimeAugments.GetHighestStaticThreadStaticIndex(typeManagerHandle); + if (!_maxThreadLocalIndex.TryGetValue(typeManagerHandle.GetIntPtrUNSAFE(), out nint result)) + result = RuntimeAugments.GetHighestStaticThreadStaticIndex(typeManagerHandle); - _maxThreadLocalIndex[typeManagerHandle.GetIntPtrUNSAFE()] = checked(++result); + uint uintResult = (uint)(nuint)result; + _maxThreadLocalIndex[typeManagerHandle.GetIntPtrUNSAFE()] = (nint)(nuint)checked(++uintResult); - return result; + return uintResult; } public void RegisterDynamicThreadStaticsInfo(RuntimeTypeHandle runtimeTypeHandle, uint offsetValue, IntPtr gcDesc) @@ -170,20 +172,18 @@ public void RegisterDynamicThreadStaticsInfo(RuntimeTypeHandle runtimeTypeHandle _threadStaticsLock.Enter(); try { - if (!_dynamicGenericsThreadStaticDescs.TryGetValue(typeManager, out LowLevelDictionary gcDescs)) - { - _dynamicGenericsThreadStaticDescs.Add(typeManager, gcDescs = new LowLevelDictionary()); - } - gcDescs.Add(offsetValue, gcDesc); + Dictionary? gcDescs = CollectionsMarshal.GetValueRefOrAddDefault(_dynamicGenericsThreadStaticDescs, typeManager, out _); + gcDescs ??= new Dictionary(); + gcDescs.Add((int)offsetValue, gcDesc); registered = true; } finally { if (!registered) { - if (_dynamicGenericsThreadStaticDescs.TryGetValue(typeManager, out LowLevelDictionary gcDescs)) + if (_dynamicGenericsThreadStaticDescs.TryGetValue(typeManager, out Dictionary gcDescs)) { - gcDescs.Remove(offsetValue); + gcDescs.Remove((int)offsetValue); } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs index cb1b6462ab3fe6..4a5994f5d773d2 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs @@ -40,7 +40,7 @@ public override bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle public override IntPtr GetThreadStaticGCDescForDynamicType(TypeManagerHandle typeManagerHandle, int index) { // We can use InstanceOrNull because we can't have a reference to a dynamic type without creating type loader first - return TypeLoaderEnvironment.InstanceOrNull.GetThreadStaticGCDescForDynamicType(typeManagerHandle, (uint)index); + return TypeLoaderEnvironment.InstanceOrNull.GetThreadStaticGCDescForDynamicType(typeManagerHandle, index); } public override IntPtr GenericLookupFromContextAndSignature(IntPtr context, IntPtr signature, out IntPtr auxResult) @@ -109,7 +109,7 @@ private static TypeLoaderEnvironment InitializeInstance() // thread safety. Using ThreadStatic instead of a lock is ok as long as the NativeReader class is // small enough in size (which is the case today). [ThreadStatic] - private static LowLevelDictionary t_moduleNativeReaders; + private static Dictionary t_moduleNativeReaders; // Eager initialization called from LibraryInitializer for the assembly. internal static void Initialize() @@ -190,10 +190,10 @@ internal static unsafe NativeReader GetNativeLayoutInfoReader(TypeManagerHandle { Debug.Assert(!moduleHandle.IsNull); - t_moduleNativeReaders ??= new LowLevelDictionary(); + t_moduleNativeReaders ??= new Dictionary(); NativeReader result; - if (t_moduleNativeReaders.TryGetValue(moduleHandle, out result)) + if (t_moduleNativeReaders.TryGetValue(moduleHandle.GetIntPtrUNSAFE(), out result)) return result; byte* pBlob; @@ -201,7 +201,7 @@ internal static unsafe NativeReader GetNativeLayoutInfoReader(TypeManagerHandle if (RuntimeAugments.FindBlob(moduleHandle, (int)ReflectionMapBlob.NativeLayoutInfo, new IntPtr(&pBlob), new IntPtr(&cbBlob))) result = new NativeReader(pBlob, cbBlob); - t_moduleNativeReaders.Add(moduleHandle, result); + t_moduleNativeReaders.Add(moduleHandle.GetIntPtrUNSAFE(), result); return result; } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs index 6391cf78abaa65..e8adc288463384 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Reflection.Runtime.General; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Internal.Metadata.NativeFormat; using Internal.NativeFormat; @@ -175,13 +176,13 @@ public Instantiation ResolveRuntimeTypeHandles(RuntimeTypeHandle[] runtimeTypeHa } // This dictionary is in every scenario - create it eagerly - private LowLevelDictionary _runtimeTypeHandleResolutionCache = - new LowLevelDictionary(); + private Dictionary _runtimeTypeHandleResolutionCache = + new Dictionary(); public TypeDesc ResolveRuntimeTypeHandle(RuntimeTypeHandle rtth) { TypeDesc returnedType; - if (_runtimeTypeHandleResolutionCache.TryGetValue(rtth, out returnedType)) + if (_runtimeTypeHandleResolutionCache.TryGetValue(rtth.Value, out returnedType)) return returnedType; if (rtth.Equals(CanonType.RuntimeTypeHandle)) @@ -271,7 +272,7 @@ public TypeDesc ResolveRuntimeTypeHandle(RuntimeTypeHandle rtth) returnedType.SetRuntimeTypeHandleUnsafe(rtth); } - _runtimeTypeHandleResolutionCache.Add(rtth, returnedType); + _runtimeTypeHandleResolutionCache.Add(rtth.Value, returnedType); return returnedType.WithDebugName(); } @@ -436,7 +437,7 @@ internal MethodDesc ResolveRuntimeMethod(bool unboxingStub, DefType owningType, return _runtimeMethods.GetOrCreateValue(new RuntimeMethodKey(unboxingStub, owningType, nameAndSignature)); } - private LowLevelDictionary _genericTypeInstances; + private Dictionary _genericTypeInstances; /// /// Get a DefType that is the generic instantiation of an open generic type over instantiation arguments @@ -447,18 +448,16 @@ public DefType ResolveGenericInstantiation(DefType typeDef, Instantiation argume { Debug.Assert(typeDef.Instantiation.IsNull || typeDef.Instantiation.Length == arguments.Length); - _genericTypeInstances ??= new LowLevelDictionary(); + _genericTypeInstances ??= new Dictionary(); GenericTypeInstanceKey key = new GenericTypeInstanceKey(typeDef, arguments); - DefType result; - if (!_genericTypeInstances.TryGetValue(key, out result)) + ref DefType? result = ref CollectionsMarshal.GetValueRefOrAddDefault(_genericTypeInstances, key, out bool exists); + if (!exists) { NoMetadataType nmTypeDef = (NoMetadataType)typeDef; Debug.Assert(RuntimeAugments.IsGenericTypeDefinition(nmTypeDef.RuntimeTypeHandle)); result = new NoMetadataType(this, nmTypeDef.RuntimeTypeHandle, nmTypeDef, arguments, key.GetHashCode()); - - _genericTypeInstances.Add(key, result); } return result.WithDebugName(); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj index 367dd4750479e5..faaa6b5f99f560 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj @@ -1,4 +1,4 @@ - + disable TYPE_LOADER_IMPLEMENTATION;$(DefineConstants) @@ -44,9 +44,6 @@ ArrayBuilder.cs - - LowLevelDictionary.cs - NotImplemented.cs