Skip to content
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 @@ -112,7 +112,7 @@ internal static EmitBaseline.MetadataSymbols GetOrCreateMetadataSymbols(EmitBase
internal static SynthesizedTypeMaps GetSynthesizedTypesFromMetadata(MetadataReader reader, MetadataDecoder metadataDecoder)
{
var anonymousTypes = ImmutableSegmentedDictionary.CreateBuilder<AnonymousTypeKey, AnonymousTypeValue>();
var anonymousDelegatesWithIndexedNames = new Dictionary<AnonymousDelegateWithIndexedNamePartialKey, ArrayBuilder<AnonymousTypeValue>>();
var anonymousDelegatesWithIndexedNames = PooledDictionary<AnonymousDelegateWithIndexedNamePartialKey, ArrayBuilder<AnonymousTypeValue>>.GetInstance();
var anonymousDelegates = ImmutableSegmentedDictionary.CreateBuilder<SynthesizedDelegateKey, SynthesizedDelegateValue>();

foreach (var handle in reader.TypeDefinitions)
Expand Down
13 changes: 10 additions & 3 deletions src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static bool TryAdd<TKey, TValue>(
}
#endif

public static void AddPooled<K, V>(this IDictionary<K, ArrayBuilder<V>> dictionary, K key, V value)
public static void AddPooled<K, V>(this Dictionary<K, ArrayBuilder<V>> dictionary, K key, V value)
where K : notnull
{
if (!dictionary.TryGetValue(key, out var values))
Expand All @@ -88,15 +88,22 @@ public static void AddPooled<K, V>(this IDictionary<K, ArrayBuilder<V>> dictiona
values.Add(value);
}

public static ImmutableSegmentedDictionary<K, ImmutableArray<V>> ToImmutableSegmentedDictionaryAndFree<K, V>(this IReadOnlyDictionary<K, ArrayBuilder<V>> builder)
/// <summary>
/// Converts the passed in dictionary to an <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/>, where all
/// the values in the passed builder will be converted to an <see cref="ImmutableArray{T}"/> using <see
/// cref="ArrayBuilder{T}.ToImmutableAndFree"/>. The <paramref name="dictionary"/> will be freed at the end of
/// this method as well, and should not be used afterwards.
/// </summary>
public static ImmutableSegmentedDictionary<K, ImmutableArray<V>> ToImmutableSegmentedDictionaryAndFree<K, V>(this PooledDictionary<K, ArrayBuilder<V>> dictionary)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this just helps with code hygiene around repetition.

where K : notnull
{
var result = ImmutableSegmentedDictionary.CreateBuilder<K, ImmutableArray<V>>();
foreach (var (key, values) in builder)
foreach (var (key, values) in dictionary)
{
result.Add(key, values.ToImmutableAndFree());
}

dictionary.Free();
return result.ToImmutable();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;

Expand All @@ -17,16 +18,25 @@ internal partial class AnalyzerDriver<TLanguageKindEnum> : AnalyzerDriver where
/// </summary>
private sealed class GroupedAnalyzerActions : IGroupedAnalyzerActions
{
public static readonly GroupedAnalyzerActions Empty = new GroupedAnalyzerActions(ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)>.Empty, AnalyzerActions.Empty);
public static readonly GroupedAnalyzerActions Empty = new GroupedAnalyzerActions(
ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)>.Empty,
ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<DiagnosticAnalyzer>>.Empty,
AnalyzerActions.Empty);

private GroupedAnalyzerActions(ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)> groupedActionsAndAnalyzers, in AnalyzerActions analyzerActions)
private GroupedAnalyzerActions(
ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)> groupedActionsAndAnalyzers,
ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<DiagnosticAnalyzer>> analyzersByKind,
in AnalyzerActions analyzerActions)
{
GroupedActionsByAnalyzer = groupedActionsAndAnalyzers;
AnalyzerActions = analyzerActions;
AnalyzersByKind = analyzersByKind;
}

public ImmutableArray<(DiagnosticAnalyzer analyzer, GroupedAnalyzerActionsForAnalyzer groupedActions)> GroupedActionsByAnalyzer { get; }

public ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<DiagnosticAnalyzer>> AnalyzersByKind { get; }

public AnalyzerActions AnalyzerActions { get; }

public bool IsEmpty
Expand All @@ -48,7 +58,8 @@ public static GroupedAnalyzerActions Create(DiagnosticAnalyzer analyzer, in Anal

var groupedActions = new GroupedAnalyzerActionsForAnalyzer(analyzer, analyzerActions, analyzerActionsNeedFiltering: false);
var groupedActionsAndAnalyzers = ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)>.Empty.Add((analyzer, groupedActions));
return new GroupedAnalyzerActions(groupedActionsAndAnalyzers, in analyzerActions);
var analyzersByKind = CreateAnalyzersByKind(groupedActionsAndAnalyzers);
return new GroupedAnalyzerActions(groupedActionsAndAnalyzers, analyzersByKind, in analyzerActions);
}

public static GroupedAnalyzerActions Create(ImmutableArray<DiagnosticAnalyzer> analyzers, in AnalyzerActions analyzerActions)
Expand All @@ -58,7 +69,8 @@ public static GroupedAnalyzerActions Create(ImmutableArray<DiagnosticAnalyzer> a
var groups = analyzers.SelectAsArray(
(analyzer, analyzerActions) => (analyzer, new GroupedAnalyzerActionsForAnalyzer(analyzer, analyzerActions, analyzerActionsNeedFiltering: true)),
analyzerActions);
return new GroupedAnalyzerActions(groups, in analyzerActions);
var analyzersByKind = CreateAnalyzersByKind(groups);
return new GroupedAnalyzerActions(groups, analyzersByKind, in analyzerActions);
}

IGroupedAnalyzerActions IGroupedAnalyzerActions.Append(IGroupedAnalyzerActions igroupedAnalyzerActions)
Expand All @@ -74,7 +86,22 @@ IGroupedAnalyzerActions IGroupedAnalyzerActions.Append(IGroupedAnalyzerActions i

var newGroupedActions = GroupedActionsByAnalyzer.AddRange(groupedAnalyzerActions.GroupedActionsByAnalyzer);
var newAnalyzerActions = AnalyzerActions.Append(groupedAnalyzerActions.AnalyzerActions);
return new GroupedAnalyzerActions(newGroupedActions, newAnalyzerActions);
var analyzersByKind = CreateAnalyzersByKind(newGroupedActions);
return new GroupedAnalyzerActions(newGroupedActions, analyzersByKind, newAnalyzerActions);
}

private static ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<DiagnosticAnalyzer>> CreateAnalyzersByKind(ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)> groupedActionsAndAnalyzers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a marow win by getting us to O(1) lookups per syntax node kind, which is an uber hot spot while doing analyzers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A major win? Or a narrow win? I feel like I could read the typo either way :P

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol. Major.

{
var analyzersByKind = PooledDictionary<TLanguageKindEnum, ArrayBuilder<DiagnosticAnalyzer>>.GetInstance();
foreach (var (analyzer, groupedActionsForAnalyzer) in groupedActionsAndAnalyzers)
{
foreach (var (kind, _) in groupedActionsForAnalyzer.NodeActionsByAnalyzerAndKind)
{
analyzersByKind.AddPooled(kind, analyzer);
}
}

return analyzersByKind.ToImmutableSegmentedDictionaryAndFree();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2611,10 +2611,26 @@ void executeNodeActions()

void executeNodeActionsByKind(ArrayBuilder<SyntaxNode> nodesToAnalyze, GroupedAnalyzerActions groupedActions, bool arePerSymbolActions)
{
if (groupedActions.GroupedActionsByAnalyzer.Length == 0)
{
return;
}

var analyzersForNodes = PooledHashSet<DiagnosticAnalyzer>.GetInstance();
foreach (var node in nodesToAnalyze)
{
if (groupedActions.AnalyzersByKind.TryGetValue(_getKind(node), out var analyzersForKind))
{
foreach (var analyzer in analyzersForKind)
{
analyzersForNodes.Add(analyzer);
}
}
}

foreach (var (analyzer, groupedActionsForAnalyzer) in groupedActions.GroupedActionsByAnalyzer)
{
var nodeActionsByKind = groupedActionsForAnalyzer.NodeActionsByAnalyzerAndKind;
if (nodeActionsByKind.IsEmpty || !analysisScope.Contains(analyzer))
if (!analyzersForNodes.Contains(analyzer) || !analysisScope.Contains(analyzer))
{
continue;
}
Expand Down Expand Up @@ -2642,6 +2658,8 @@ void executeNodeActionsByKind(ArrayBuilder<SyntaxNode> nodesToAnalyze, GroupedAn
}
}

analyzersForNodes.Free();

void executeSyntaxNodeActions(
DiagnosticAnalyzer analyzer,
GroupedAnalyzerActionsForAnalyzer groupedActionsForAnalyzer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,19 +932,11 @@ internal static ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<S
{
foreach (var kind in nodeAction.Kinds)
{
if (!nodeActionsByKind.TryGetValue(kind, out var actionsForKind))
{
nodeActionsByKind.Add(kind, actionsForKind = ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>.GetInstance());
}

actionsForKind.Add(nodeAction);
nodeActionsByKind.AddPooled(kind, nodeAction);
}
}

var tuples = nodeActionsByKind.Select(kvp => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableAndFree()));
var map = ImmutableSegmentedDictionary.CreateRange(tuples);
nodeActionsByKind.Free();
return map;
return nodeActionsByKind.ToImmutableSegmentedDictionaryAndFree();
}

/// <summary>
Expand Down Expand Up @@ -1031,19 +1023,11 @@ internal static ImmutableSegmentedDictionary<OperationKind, ImmutableArray<Opera
{
foreach (var kind in operationAction.Kinds)
{
if (!operationActionsByKind.TryGetValue(kind, out var actionsForKind))
{
operationActionsByKind.Add(kind, actionsForKind = ArrayBuilder<OperationAnalyzerAction>.GetInstance());
}

actionsForKind.Add(operationAction);
operationActionsByKind.AddPooled(kind, operationAction);
}
}

var tuples = operationActionsByKind.Select(kvp => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableAndFree()));
var map = ImmutableSegmentedDictionary.CreateRange(tuples);
operationActionsByKind.Free();
return map;
return operationActionsByKind.ToImmutableSegmentedDictionaryAndFree();
}

/// <summary>
Expand Down
Loading