Skip to content

Commit

Permalink
Avoid creating Location instances in SyntaxNodeLocationComparer
Browse files Browse the repository at this point in the history
Avoids 7GB allocations (5.2% of total) reported in a performance trace.
  • Loading branch information
sharwell committed Sep 7, 2021
1 parent 639d8c9 commit 7f5a439
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 3 deletions.
11 changes: 11 additions & 0 deletions src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3860,6 +3860,17 @@ internal override int CompareSourceLocations(SyntaxReference loc1, SyntaxReferen
return loc1.Span.Start - loc2.Span.Start;
}

internal override int CompareSourceLocations(SyntaxNode loc1, SyntaxNode loc2)
{
var comparison = CompareSyntaxTreeOrdering(loc1.SyntaxTree, loc2.SyntaxTree);
if (comparison != 0)
{
return comparison;
}

return loc1.Span.Start - loc2.Span.Start;
}

/// <summary>
/// Return true if there is a source declaration symbol name that meets given predicate.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/Core/Portable/Compilation/Compilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3236,6 +3236,12 @@ internal int CompareSyntaxTreeOrdering(SyntaxTree tree1, SyntaxTree tree2)
/// </summary>
internal abstract int CompareSourceLocations(SyntaxReference loc1, SyntaxReference loc2);

/// <summary>
/// Compare two source locations, using their containing trees, and then by Span.First within a tree.
/// Can be used to get a total ordering on declarations, for example.
/// </summary>
internal abstract int CompareSourceLocations(SyntaxNode loc1, SyntaxNode loc2);

/// <summary>
/// Return the lexically first of two locations.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis
{
Expand Down Expand Up @@ -33,7 +31,7 @@ public int Compare(SyntaxNode? x, SyntaxNode? y)
}
else
{
return _compilation.CompareSourceLocations(x.GetLocation(), y.GetLocation());
return _compilation.CompareSourceLocations(x, y);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return LexicalSortKey.Compare(first, second, Me)
End Function

''' <summary>
''' Compare two source locations, using their containing trees, and then by Span.First within a tree.
''' Can be used to get a total ordering on declarations, for example.
''' </summary>
Friend Overrides Function CompareSourceLocations(first As SyntaxNode, second As SyntaxNode) As Integer
Return LexicalSortKey.Compare(first, second, Me)
End Function

Friend Overrides Function GetSyntaxTreeOrdinal(tree As SyntaxTree) As Integer
Debug.Assert(Me.ContainsSyntaxTree(tree))
Return _syntaxTreeOrdinalMap(tree)
Expand Down
13 changes: 13 additions & 0 deletions src/Compilers/VisualBasic/Portable/Symbols/LexicalSortKey.vb
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return LexicalSortKey.Compare(firstKey, secondKey)
End Function

Public Shared Function Compare(first As SyntaxNode, second As SyntaxNode, compilation As VisualBasicCompilation) As Integer
' This is a shortcut to avoid building complete keys for the case when both locations belong to the same tree.
' Also saves us in some speculative SemanticModel scenarios when the tree we are dealing with doesn't belong to
' the compilation and an attempt of building the LexicalSortKey will simply assert and crash.
If first.SyntaxTree IsNot Nothing AndAlso first.SyntaxTree Is second.SyntaxTree Then
Return first.Span.Start - second.Span.Start
End If

Dim firstKey = New LexicalSortKey(first.SyntaxTree, first.SpanStart, compilation)
Dim secondKey = New LexicalSortKey(second.SyntaxTree, second.SpanStart, compilation)
Return LexicalSortKey.Compare(firstKey, secondKey)
End Function

Public Shared Function First(xSortKey As LexicalSortKey, ySortKey As LexicalSortKey) As LexicalSortKey
Dim comparison As Integer = Compare(xSortKey, ySortKey)
Return If(comparison > 0, ySortKey, xSortKey)
Expand Down

0 comments on commit 7f5a439

Please sign in to comment.