diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs index 5fcbbead0836d..21d4bd7163694 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs @@ -250,8 +250,16 @@ public override bool IsTriviaWithEndOfLine() } // Use conditional weak table so we always return same identity for structured trivia - private static readonly ConditionalWeakTable>> s_structuresTable - = new ConditionalWeakTable>>(); + // + // As there are commonly few structured trivia per parent, use a SmallDictionary for + // mapping from trivia to StructuredTriviaSyntax. Testing against roslyn, of parents + // containing structured trivia: + // 81.2% contain 1 structured trivia + // 96.5% contain 2 or fewer structured trivia + // 99.6% contain 4 or fewer structured trivia + // 100% contain 7 or fewer structured trivia + private static readonly ConditionalWeakTable> s_structuresTable + = new ConditionalWeakTable>(); /// /// Gets the syntax node represented the structure of this trivia, if any. The HasStructure property can be used to @@ -270,36 +278,29 @@ public override bool IsTriviaWithEndOfLine() /// public override SyntaxNode GetStructure(Microsoft.CodeAnalysis.SyntaxTrivia trivia) { - if (trivia.HasStructure) + if (!trivia.HasStructure) { - var parent = trivia.Token.Parent; - if (parent != null) - { - SyntaxNode structure; - var structsInParent = s_structuresTable.GetOrCreateValue(parent); - lock (structsInParent) - { - if (!structsInParent.TryGetValue(trivia, out var weakStructure)) - { - structure = CSharp.Syntax.StructuredTriviaSyntax.Create(trivia); - structsInParent.Add(trivia, new WeakReference(structure)); - } - else if (!weakStructure.TryGetTarget(out structure)) - { - structure = CSharp.Syntax.StructuredTriviaSyntax.Create(trivia); - weakStructure.SetTarget(structure); - } - } + return null; + } - return structure; - } - else + var parent = trivia.Token.Parent; + if (parent is null) + { + return CSharp.Syntax.StructuredTriviaSyntax.Create(trivia); + } + + SyntaxNode structure; + var structsInParent = s_structuresTable.GetOrCreateValue(parent); + lock (structsInParent) + { + if (!structsInParent.TryGetValue(trivia, out structure)) { - return CSharp.Syntax.StructuredTriviaSyntax.Create(trivia); + structure = CSharp.Syntax.StructuredTriviaSyntax.Create(trivia); + structsInParent.Add(trivia, structure); } } - return null; + return structure; } } } diff --git a/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxNode.vb b/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxNode.vb index 68be901611ea3..ae660e6913d35 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxNode.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/InternalSyntax/SyntaxNode.vb @@ -203,7 +203,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax End Function ' Use conditional weak table so we always return same identity for structured trivia - Private Shared ReadOnly s_structuresTable As New ConditionalWeakTable(Of SyntaxNode, Dictionary(Of Microsoft.CodeAnalysis.SyntaxTrivia, WeakReference(Of SyntaxNode))) + ' + ' As there are commonly few structured trivia per parent, use a SmallDictionary for + ' mapping from trivia to StructuredTriviaSyntax. Testing against roslyn, of parents + ' containing structured trivia: + ' 81.2% contain 1 structured trivia + ' 96.5% contain 2 or fewer structured trivia + ' 99.6% contain 4 or fewer structured trivia + ' 100% contain 7 or fewer structured trivia + Private Shared ReadOnly s_structuresTable As New ConditionalWeakTable(Of SyntaxNode, SmallDictionary(Of Microsoft.CodeAnalysis.SyntaxTrivia, SyntaxNode)) Public Overrides Function GetStructure(trivia As Microsoft.CodeAnalysis.SyntaxTrivia) As SyntaxNode If Not trivia.HasStructure Then @@ -219,13 +227,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Dim structsInParent = s_structuresTable.GetOrCreateValue(parent) SyncLock structsInParent - Dim weakStructure As WeakReference(Of SyntaxNode) = Nothing - If Not structsInParent.TryGetValue(trivia, weakStructure) Then + If Not structsInParent.TryGetValue(trivia, [structure]) Then [structure] = VisualBasic.Syntax.StructuredTriviaSyntax.Create(trivia) - structsInParent.Add(trivia, New WeakReference(Of SyntaxNode)([structure])) - ElseIf Not weakStructure.TryGetTarget([structure]) Then - [structure] = VisualBasic.Syntax.StructuredTriviaSyntax.Create(trivia) - weakStructure.SetTarget([structure]) + structsInParent.Add(trivia, [structure]) End If End SyncLock