Skip to content

Commit

Permalink
Merge pull request #54146 from sharwell/faster-cache
Browse files Browse the repository at this point in the history
Use segmented collection for faster declaration cache
  • Loading branch information
sharwell authored Jun 17, 2021
2 parents 0dd4dec + 22fda83 commit 0983302
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4333,7 +4333,7 @@ protected override bool ShouldCheckTypeForMembers(MergedTypeDeclaration current)
{
foreach (SingleTypeDeclaration typeDecl in current.Declarations)
{
if (typeDecl.MemberNames.Contains(_name))
if (typeDecl.MemberNames.ContainsKey(_name))
{
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ public static bool ContainsName(
mergedRoot,
n => n == name,
filter,
t => t.MemberNames.Contains(name),
t => t.MemberNames.ContainsKey(name),
cancellationToken);
}

Expand All @@ -292,7 +292,7 @@ public static bool ContainsName(
mergedRoot, predicate, filter,
t =>
{
foreach (var name in t.MemberNames)
foreach (var (name, _) in t.MemberNames)
{
if (predicate(name))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
Expand Down Expand Up @@ -114,7 +115,7 @@ private ImmutableArray<SingleNamespaceOrTypeDeclaration> VisitNamespaceChildren(
return childrenBuilder.ToImmutableAndFree();
}

private static SingleNamespaceOrTypeDeclaration CreateImplicitClass(ImmutableHashSet<string> memberNames, SyntaxReference container, SingleTypeDeclaration.TypeDeclarationFlags declFlags)
private static SingleNamespaceOrTypeDeclaration CreateImplicitClass(ImmutableSegmentedDictionary<string, VoidResult> memberNames, SyntaxReference container, SingleTypeDeclaration.TypeDeclarationFlags declFlags)
{
return new SingleTypeDeclaration(
kind: DeclarationKind.ImplicitClass,
Expand All @@ -141,7 +142,7 @@ private static SingleNamespaceOrTypeDeclaration CreateSimpleProgram(GlobalStatem
(hasReturnWithExpression ? SingleTypeDeclaration.TypeDeclarationFlags.HasReturnWithExpression : SingleTypeDeclaration.TypeDeclarationFlags.None),
syntaxReference: firstGlobalStatement.SyntaxTree.GetReference(firstGlobalStatement.Parent),
nameLocation: new SourceLocation(firstGlobalStatement.GetFirstToken()),
memberNames: ImmutableHashSet<string>.Empty,
memberNames: ImmutableSegmentedDictionary<string, VoidResult>.Empty,
children: ImmutableArray<SingleTypeDeclaration>.Empty,
diagnostics: ImmutableArray<Diagnostic>.Empty);
}
Expand Down Expand Up @@ -209,7 +210,7 @@ private static ImmutableArray<ReferenceDirective> GetReferenceDirectives(Compila
private SingleNamespaceOrTypeDeclaration CreateScriptClass(
CompilationUnitSyntax parent,
ImmutableArray<SingleTypeDeclaration> children,
ImmutableHashSet<string> memberNames,
ImmutableSegmentedDictionary<string, VoidResult> memberNames,
SingleTypeDeclaration.TypeDeclarationFlags declFlags)
{
Debug.Assert(parent.Kind() == SyntaxKind.CompilationUnit && _syntaxTree.Options.Kind != SourceCodeKind.Regular);
Expand Down Expand Up @@ -510,7 +511,7 @@ public override SingleNamespaceOrTypeDeclaration VisitDelegateDeclaration(Delega
arity: node.Arity,
syntaxReference: _syntaxTree.GetReference(node),
nameLocation: new SourceLocation(node.Identifier),
memberNames: ImmutableHashSet<string>.Empty,
memberNames: ImmutableSegmentedDictionary<string, VoidResult>.Empty,
children: ImmutableArray<SingleTypeDeclaration>.Empty,
diagnostics: diagnostics.ToReadOnlyAndFree());
}
Expand All @@ -528,7 +529,7 @@ public override SingleNamespaceOrTypeDeclaration VisitEnumDeclaration(EnumDeclar
declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasBaseDeclarations;
}

ImmutableHashSet<string> memberNames = GetEnumMemberNames(members, ref declFlags);
ImmutableSegmentedDictionary<string, VoidResult> memberNames = GetEnumMemberNames(members, ref declFlags);

var diagnostics = DiagnosticBag.GetInstance();
var modifiers = node.Modifiers.ToDeclarationModifiers(diagnostics: diagnostics);
Expand All @@ -546,18 +547,18 @@ public override SingleNamespaceOrTypeDeclaration VisitEnumDeclaration(EnumDeclar
diagnostics: diagnostics.ToReadOnlyAndFree());
}

private static readonly ObjectPool<ImmutableHashSet<string>.Builder> s_memberNameBuilderPool =
new ObjectPool<ImmutableHashSet<string>.Builder>(() => ImmutableHashSet.CreateBuilder<string>());
private static readonly ObjectPool<ImmutableSegmentedDictionary<string, VoidResult>.Builder> s_memberNameBuilderPool =
new ObjectPool<ImmutableSegmentedDictionary<string, VoidResult>.Builder>(() => ImmutableSegmentedDictionary.CreateBuilder<string, VoidResult>());

private static ImmutableHashSet<string> ToImmutableAndFree(ImmutableHashSet<string>.Builder builder)
private static ImmutableSegmentedDictionary<string, VoidResult> ToImmutableAndFree(ImmutableSegmentedDictionary<string, VoidResult>.Builder builder)
{
var result = builder.ToImmutable();
builder.Clear();
s_memberNameBuilderPool.Free(builder);
return result;
}

private static ImmutableHashSet<string> GetEnumMemberNames(SeparatedSyntaxList<EnumMemberDeclarationSyntax> members, ref SingleTypeDeclaration.TypeDeclarationFlags declFlags)
private static ImmutableSegmentedDictionary<string, VoidResult> GetEnumMemberNames(SeparatedSyntaxList<EnumMemberDeclarationSyntax> members, ref SingleTypeDeclaration.TypeDeclarationFlags declFlags)
{
var cnt = members.Count;

Expand All @@ -570,7 +571,7 @@ private static ImmutableHashSet<string> GetEnumMemberNames(SeparatedSyntaxList<E
bool anyMemberHasAttributes = false;
foreach (var member in members)
{
memberNamesBuilder.Add(member.Identifier.ValueText);
memberNamesBuilder.TryAdd(member.Identifier.ValueText);
if (!anyMemberHasAttributes && member.AttributeLists.Any())
{
anyMemberHasAttributes = true;
Expand All @@ -585,7 +586,7 @@ private static ImmutableHashSet<string> GetEnumMemberNames(SeparatedSyntaxList<E
return ToImmutableAndFree(memberNamesBuilder);
}

private static ImmutableHashSet<string> GetNonTypeMemberNames(
private static ImmutableSegmentedDictionary<string, VoidResult> GetNonTypeMemberNames(
CoreInternalSyntax.SyntaxList<Syntax.InternalSyntax.MemberDeclarationSyntax> members, ref SingleTypeDeclaration.TypeDeclarationFlags declFlags, bool skipGlobalStatements = false)
{
bool anyMethodHadExtensionSyntax = false;
Expand Down Expand Up @@ -707,7 +708,7 @@ private static bool CheckMemberForAttributes(Syntax.InternalSyntax.CSharpSyntaxN
}

private static void AddNonTypeMemberNames(
Syntax.InternalSyntax.CSharpSyntaxNode member, ImmutableHashSet<string>.Builder set, ref bool anyNonTypeMembers, bool skipGlobalStatements)
Syntax.InternalSyntax.CSharpSyntaxNode member, ImmutableSegmentedDictionary<string, VoidResult>.Builder set, ref bool anyNonTypeMembers, bool skipGlobalStatements)
{
switch (member.Kind)
{
Expand All @@ -718,7 +719,7 @@ private static void AddNonTypeMemberNames(
int numFieldDeclarators = fieldDeclarators.Count;
for (int i = 0; i < numFieldDeclarators; i++)
{
set.Add(fieldDeclarators[i].Identifier.ValueText);
set.TryAdd(fieldDeclarators[i].Identifier.ValueText);
}
break;

Expand All @@ -729,7 +730,7 @@ private static void AddNonTypeMemberNames(
int numEventDeclarators = eventDeclarators.Count;
for (int i = 0; i < numEventDeclarators; i++)
{
set.Add(eventDeclarators[i].Identifier.ValueText);
set.TryAdd(eventDeclarators[i].Identifier.ValueText);
}
break;

Expand All @@ -742,7 +743,7 @@ private static void AddNonTypeMemberNames(
var methodDecl = (Syntax.InternalSyntax.MethodDeclarationSyntax)member;
if (methodDecl.ExplicitInterfaceSpecifier == null)
{
set.Add(methodDecl.Identifier.ValueText);
set.TryAdd(methodDecl.Identifier.ValueText);
}
break;

Expand All @@ -752,7 +753,7 @@ private static void AddNonTypeMemberNames(
var propertyDecl = (Syntax.InternalSyntax.PropertyDeclarationSyntax)member;
if (propertyDecl.ExplicitInterfaceSpecifier == null)
{
set.Add(propertyDecl.Identifier.ValueText);
set.TryAdd(propertyDecl.Identifier.ValueText);
}
break;

Expand All @@ -762,25 +763,25 @@ private static void AddNonTypeMemberNames(
var eventDecl = (Syntax.InternalSyntax.EventDeclarationSyntax)member;
if (eventDecl.ExplicitInterfaceSpecifier == null)
{
set.Add(eventDecl.Identifier.ValueText);
set.TryAdd(eventDecl.Identifier.ValueText);
}
break;

case SyntaxKind.ConstructorDeclaration:
anyNonTypeMembers = true;
set.Add(((Syntax.InternalSyntax.ConstructorDeclarationSyntax)member).Modifiers.Any((int)SyntaxKind.StaticKeyword)
set.TryAdd(((Syntax.InternalSyntax.ConstructorDeclarationSyntax)member).Modifiers.Any((int)SyntaxKind.StaticKeyword)
? WellKnownMemberNames.StaticConstructorName
: WellKnownMemberNames.InstanceConstructorName);
break;

case SyntaxKind.DestructorDeclaration:
anyNonTypeMembers = true;
set.Add(WellKnownMemberNames.DestructorName);
set.TryAdd(WellKnownMemberNames.DestructorName);
break;

case SyntaxKind.IndexerDeclaration:
anyNonTypeMembers = true;
set.Add(WellKnownMemberNames.Indexer);
set.TryAdd(WellKnownMemberNames.Indexer);
break;

case SyntaxKind.OperatorDeclaration:
Expand All @@ -793,7 +794,7 @@ private static void AddNonTypeMemberNames(
if (opDecl.ExplicitInterfaceSpecifier == null)
{
var name = OperatorFacts.OperatorNameFromDeclaration(opDecl);
set.Add(name);
set.TryAdd(name);
}
}
break;
Expand All @@ -808,7 +809,7 @@ private static void AddNonTypeMemberNames(
if (opDecl.ExplicitInterfaceSpecifier == null)
{
var name = OperatorFacts.OperatorNameFromDeclaration(opDecl);
set.Add(name);
set.TryAdd(name);
}
}
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public ICollection<string> MemberNames
{
if (_lazyMemberNames == null)
{
var names = UnionCollection<string>.Create(this.Declarations, d => d.MemberNames);
var names = UnionCollection<string>.Create(this.Declarations, d => d.MemberNames.Keys);
Interlocked.CompareExchange(ref _lazyMemberNames, names, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Collections;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp
Expand Down Expand Up @@ -53,7 +54,7 @@ internal SingleTypeDeclaration(
TypeDeclarationFlags declFlags,
SyntaxReference syntaxReference,
SourceLocation nameLocation,
ImmutableHashSet<string> memberNames,
ImmutableSegmentedDictionary<string, VoidResult> memberNames,
ImmutableArray<SingleTypeDeclaration> children,
ImmutableArray<Diagnostic> diagnostics)
: base(name, syntaxReference, nameLocation, diagnostics)
Expand Down Expand Up @@ -100,7 +101,7 @@ public DeclarationModifiers Modifiers
}
}

public ImmutableHashSet<string> MemberNames { get; }
public ImmutableSegmentedDictionary<string, VoidResult> MemberNames { get; }

public bool AnyMemberHasExtensionMethodSyntax
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Collections
{
internal static class ImmutableSegmentedDictionaryBuilderExtensions
{
public static bool TryAdd<T>(
this ImmutableSegmentedDictionary<T, VoidResult>.Builder dictionary,
T value)
where T : notnull
{
#if NETCOREAPP
return dictionary.TryAdd(value, default);
#else
if (dictionary.ContainsKey(value))
return false;

dictionary[value] = default;
return true;
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ namespace Roslyn.Utilities
/// <summary>
/// Explicitly indicates result is void
/// </summary>
internal struct VoidResult { }
internal readonly struct VoidResult { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\..\Compilers\Core\Portable\InternalUtilities\SpecializedCollections.Singleton.Enumerator`1.cs" Link="InternalUtilities\SpecializedCollections.Singleton.Enumerator`1.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\..\Compilers\Core\Portable\InternalUtilities\StringExtensions.cs" Link="InternalUtilities\StringExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\..\Compilers\Core\Portable\InternalUtilities\ValueTaskFactory.cs" Link="InternalUtilities\ValueTaskFactory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\..\Compilers\Core\Portable\InternalUtilities\VoidResult.cs" Link="InternalUtilities\VoidResult.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\..\Compilers\Core\Portable\InternalUtilities\YieldAwaitableExtensions.cs" Link="InternalUtilities\YieldAwaitableExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\..\Compilers\Core\Portable\Syntax\SyntaxTreeExtensions.cs" Link="Syntax\SyntaxTreeExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\..\Compilers\Core\Portable\Collections\ImmutableArrayExtensions.cs" Link="Collections\ImmutableArrayExtensions.cs" />
Expand Down Expand Up @@ -453,7 +454,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ValuesSources\WeaklyCachedRecoverableValueSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ValuesSources\WeaklyCachedValueSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\ValuesSources\WeakValueSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\VoidResult.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Utilities\WeakEventHandler.cs" />
</ItemGroup>
<ItemGroup>
Expand Down

0 comments on commit 0983302

Please sign in to comment.