Small perf improvement in TokenizerBackedParser.Accept and ReadWhile. (dotnet/aspnetcore-tooling#1882)

In the razor perf typing test, Accept was showing 27 ms allocating enumerators. Additionally, modified ReadWhile to only allocate if it would return a non-empty collection (and to not use the complexity introduced by using yield enumerators)\n\nCommit migrated from 27a14af36a
This commit is contained in:
Todd Grunke 2020-05-11 10:28:31 -07:00 committed by GitHub
parent 485924edd2
commit a70de6b67b
3 changed files with 24 additions and 26 deletions

View File

@ -893,7 +893,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
}
}
protected bool TryParseDirective(in SyntaxListBuilder<RazorSyntaxNode> builder, IEnumerable<SyntaxToken> whitespace, CSharpTransitionSyntax transition, string directive)
protected bool TryParseDirective(in SyntaxListBuilder<RazorSyntaxNode> builder, IReadOnlyList<SyntaxToken> whitespace, CSharpTransitionSyntax transition, string directive)
{
if (_directiveParserMap.TryGetValue(directive, out var handler))
{
@ -1679,7 +1679,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
}
}
private bool TryParseKeyword(in SyntaxListBuilder<RazorSyntaxNode> builder, IEnumerable<SyntaxToken> whitespace, CSharpTransitionSyntax transition)
private bool TryParseKeyword(in SyntaxListBuilder<RazorSyntaxNode> builder, IReadOnlyList<SyntaxToken> whitespace, CSharpTransitionSyntax transition)
{
var result = CSharpTokenizer.GetTokenKeyword(CurrentToken);
Debug.Assert(CurrentToken.Kind == SyntaxKind.Keyword && result.HasValue);
@ -2387,7 +2387,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
}
}
private IEnumerable<SyntaxToken> SkipToNextImportantToken(in SyntaxListBuilder<RazorSyntaxNode> builder)
private IReadOnlyList<SyntaxToken> SkipToNextImportantToken(in SyntaxListBuilder<RazorSyntaxNode> builder)
{
while (!EndOfFile)
{
@ -2406,7 +2406,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
return whitespace;
}
}
return Enumerable.Empty<SyntaxToken>();
return Array.Empty<SyntaxToken>();
}
private void DefaultSpanContextConfig(SpanContextBuilder spanContext)

View File

@ -1085,9 +1085,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
}
}
private bool TryParseAttributeName(out IEnumerable<SyntaxToken> nameTokens)
private bool TryParseAttributeName(out IReadOnlyList<SyntaxToken> nameTokens)
{
nameTokens = Enumerable.Empty<SyntaxToken>();
nameTokens = Array.Empty<SyntaxToken>();
//
// We are currently here <input |name="..." />
// If we encounter a transition (@) here, it can be parsed as CSharp or Markup depending on the feature flag.

View File

@ -266,14 +266,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
return true;
}
protected internal IEnumerable<SyntaxToken> ReadWhile(params SyntaxKind[] types)
protected internal IReadOnlyList<SyntaxToken> ReadWhile(Func<SyntaxToken, bool> condition)
{
return ReadWhile(token => types.Any(expected => expected == token.Kind));
}
if (!EnsureCurrent() || !condition(CurrentToken))
{
return Array.Empty<SyntaxToken>();
}
var result = new List<SyntaxToken>();
do
{
result.Add(CurrentToken);
NextToken();
}
while (EnsureCurrent() && condition(CurrentToken));
protected internal IEnumerable<SyntaxToken> ReadWhile(Func<SyntaxToken, bool> condition)
{
return ReadWhileLazy(condition).ToList();
return result;
}
protected bool AtIdentifier(bool allowKeywords)
@ -283,17 +291,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
(allowKeywords && Language.IsKeyword(CurrentToken)));
}
// Don't open this to sub classes because it's lazy but it looks eager.
// You have to advance the Enumerable to read the next characters.
internal IEnumerable<SyntaxToken> ReadWhileLazy(Func<SyntaxToken, bool> condition)
{
while (EnsureCurrent() && condition(CurrentToken))
{
yield return CurrentToken;
NextToken();
}
}
protected RazorCommentBlockSyntax ParseRazorComment()
{
if (!Language.KnowsTokenType(KnownTokenType.CommentStart) ||
@ -430,13 +427,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
protected internal void AcceptWhile(Func<SyntaxToken, bool> condition)
{
Accept(ReadWhileLazy(condition));
Accept(ReadWhile(condition));
}
protected internal void Accept(IEnumerable<SyntaxToken> tokens)
protected internal void Accept(IReadOnlyList<SyntaxToken> tokens)
{
foreach (var token in tokens)
for(int i = 0; i < tokens.Count; i++)
{
var token = tokens[i];
Accept(token);
}
}