|
8 | 8 | using System.Diagnostics; |
9 | 9 | using System.Linq; |
10 | 10 | using System.Threading; |
| 11 | +using Microsoft.CodeAnalysis.PooledObjects; |
11 | 12 | using Roslyn.Utilities; |
12 | 13 |
|
13 | 14 | namespace Microsoft.CodeAnalysis; |
@@ -55,6 +56,9 @@ public partial class ProjectDependencyGraph |
55 | 56 | private ImmutableDictionary<ProjectId, ImmutableHashSet<ProjectId>> _transitiveReferencesMap; |
56 | 57 | private ImmutableDictionary<ProjectId, ImmutableHashSet<ProjectId>> _reverseTransitiveReferencesMap; |
57 | 58 |
|
| 59 | + // Pool of ImmutableHashSet builders used in ComputeReverseReferencesMap to avoid temporary HashSet allocations. |
| 60 | + private static readonly ObjectPool<ImmutableHashSet<ProjectId>.Builder> s_reverseReferencesBuilderPool = new(static () => ImmutableHashSet.CreateBuilder<ProjectId>(), size: 256); |
| 61 | + |
58 | 62 | /// <remarks> |
59 | 63 | /// Intentionally created with a null reverseReferencesMap. Doing so indicates _lazyReverseReferencesMap |
60 | 64 | /// shouldn't be calculated until reverse reference information is requested. Once this information |
@@ -209,17 +213,36 @@ private ImmutableHashSet<ProjectId> GetProjectsThatDirectlyDependOnThisProject_N |
209 | 213 |
|
210 | 214 | private ImmutableDictionary<ProjectId, ImmutableHashSet<ProjectId>> ComputeReverseReferencesMap() |
211 | 215 | { |
212 | | - var reverseReferencesMap = new Dictionary<ProjectId, HashSet<ProjectId>>(); |
213 | | - |
| 216 | + using var _1 = PooledDictionary<ProjectId, ImmutableHashSet<ProjectId>.Builder>.GetInstance(out var reverseReferencesMapBuilders); |
214 | 217 | foreach (var (projectId, references) in _referencesMap) |
215 | 218 | { |
216 | 219 | foreach (var referencedId in references) |
217 | | - reverseReferencesMap.MultiAdd(referencedId, projectId); |
| 220 | + { |
| 221 | + if (!reverseReferencesMapBuilders.TryGetValue(referencedId, out var builder)) |
| 222 | + { |
| 223 | + builder = s_reverseReferencesBuilderPool.Allocate(); |
| 224 | + reverseReferencesMapBuilders.Add(referencedId, builder); |
| 225 | + } |
| 226 | + |
| 227 | + builder.Add(projectId); |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + // Convert all the populated ImmutableHashSet.Builder objects to ImmutableHashSets |
| 232 | + var reverseReferencesBuilder = ImmutableDictionary.CreateBuilder<ProjectId, ImmutableHashSet<ProjectId>>(); |
| 233 | + foreach (var (projectId, builder) in reverseReferencesMapBuilders) |
| 234 | + { |
| 235 | + // Realize an ImmutableHashSet from the builder |
| 236 | + var reverseReferencesForProject = builder.ToImmutableHashSet(); |
| 237 | + |
| 238 | + // Clear out the builder and release it back to the pool |
| 239 | + builder.Clear(); |
| 240 | + s_reverseReferencesBuilderPool.Free(builder); |
| 241 | + |
| 242 | + reverseReferencesBuilder.Add(projectId, reverseReferencesForProject); |
218 | 243 | } |
219 | 244 |
|
220 | | - return reverseReferencesMap |
221 | | - .Select(kvp => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableHashSet())) |
222 | | - .ToImmutableDictionary(); |
| 245 | + return reverseReferencesBuilder.ToImmutable(); |
223 | 246 | } |
224 | 247 |
|
225 | 248 | /// <summary> |
|
0 commit comments