diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs index 0a0b27d970ab8..4935978fddfce 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs @@ -6,6 +6,7 @@ using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.Immutable; +using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -19,16 +20,33 @@ namespace Microsoft.CodeAnalysis; +// On NetFx, frozen dictionary is very expensive when you give it a case insensitive comparer. This is due to +// unavoidable allocations it performs while doing its key-analysis that involve going through the non-span-aware +// culture types. So, on netfx, we use a plain ReadOnlyDictionary here. +#if NET +using FilePathToDocumentIds = FrozenDictionary>; +#else +using FilePathToDocumentIds = ReadOnlyDictionary>; +#endif + /// /// Holds on a to map and an ordering. /// internal sealed class TextDocumentStates where TState : TextDocumentState { +#if NET private static readonly ObjectPool>> s_filePathPool = new(() => new(SolutionState.FilePathComparer)); +#endif public static readonly TextDocumentStates Empty = - new([], ImmutableSortedDictionary.Create(DocumentIdComparer.Instance), FrozenDictionary>.Empty); + new([], + ImmutableSortedDictionary.Create(DocumentIdComparer.Instance), +#if NET + FilePathToDocumentIds.Empty); +#else + new(new Dictionary>())); +#endif private readonly ImmutableList _ids; @@ -39,12 +57,12 @@ internal sealed class TextDocumentStates /// private readonly ImmutableSortedDictionary _map; - private FrozenDictionary>? _filePathToDocumentIds; + private FilePathToDocumentIds? _filePathToDocumentIds; private TextDocumentStates( ImmutableList ids, ImmutableSortedDictionary map, - FrozenDictionary>? filePathToDocumentIds) + FilePathToDocumentIds? filePathToDocumentIds) { Debug.Assert(map.KeyComparer == DocumentIdComparer.Instance); @@ -342,10 +360,14 @@ public void AddDocumentIdsWithFilePath(ref TemporaryArray temporaryA : null; } - private FrozenDictionary> ComputeFilePathToDocumentIds() + private FilePathToDocumentIds ComputeFilePathToDocumentIds() { +#if NET using var pooledDictionary = s_filePathPool.GetPooledObject(); var result = pooledDictionary.Object; +#else + var result = new Dictionary>(SolutionState.FilePathComparer); +#endif foreach (var (documentId, state) in _map) { @@ -358,6 +380,10 @@ private FrozenDictionary> ComputeFilePathToDocumen : OneOrMany.Create(documentId); } +#if NET return result.ToFrozenDictionary(SolutionState.FilePathComparer); +#else + return new(result); +#endif } }