Expand the SyntaxTokenCache to contain more than just whitespace tokens.

This commit is contained in:
Todd Grunke 2020-06-08 15:37:35 -07:00
parent f56cad003f
commit 837c639041
3 changed files with 76 additions and 48 deletions

View File

@ -9,9 +9,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
{
internal static SyntaxToken Token(SyntaxKind kind, string content, params RazorDiagnostic[] diagnostics)
{
if (kind == SyntaxKind.Whitespace && diagnostics.Length == 0)
if (SyntaxTokenCache.CanBeCached(kind, diagnostics))
{
return WhitespaceTokenCache.GetToken(content);
return SyntaxTokenCache.GetCachedToken(kind, content);
}
return new SyntaxToken(kind, content, diagnostics);

View File

@ -0,0 +1,74 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
{
// Simplified version of Roslyn's SyntaxNodeCache
internal static class SyntaxTokenCache
{
private const int CacheSizeBits = 16;
private const int CacheSize = 1 << CacheSizeBits;
private const int CacheMask = CacheSize - 1;
private static readonly Entry[] s_cache = new Entry[CacheSize];
private struct Entry
{
public int Hash { get; }
public SyntaxToken Token { get; }
internal Entry(int hash, SyntaxToken token)
{
Hash = hash;
Token = token;
}
}
public static bool CanBeCached(SyntaxKind kind, params RazorDiagnostic[] diagnostics)
{
if (diagnostics.Length == 0)
{
switch (kind)
{
case SyntaxKind.CharacterLiteral:
case SyntaxKind.Dot:
case SyntaxKind.Identifier:
case SyntaxKind.IntegerLiteral:
case SyntaxKind.Keyword:
case SyntaxKind.NewLine:
case SyntaxKind.RazorCommentStar:
case SyntaxKind.RazorCommentTransition:
case SyntaxKind.StringLiteral:
case SyntaxKind.Transition:
case SyntaxKind.Whitespace:
return true;
}
}
return false;
}
public static SyntaxToken GetCachedToken(SyntaxKind kind, string content)
{
var hash = (kind, content).GetHashCode();
// Allow the upper 16 bits to contribute to the index
var indexableHash = hash ^ (hash >> 16);
var idx = indexableHash & CacheMask;
var e = s_cache[idx];
if (e.Hash == hash && e.Token.Kind == kind && e.Token.Content == content)
{
return e.Token;
}
var token = new SyntaxToken(kind, content, Array.Empty<RazorDiagnostic>());
s_cache[idx] = new Entry(hash, token);
return token;
}
}
}

View File

@ -1,46 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
{
// Simplified version of Roslyn's SyntaxNodeCache
internal static class WhitespaceTokenCache
{
private const int CacheSizeBits = 8;
private const int CacheSize = 1 << CacheSizeBits;
private const int CacheMask = CacheSize - 1;
private static readonly Entry[] s_cache = new Entry[CacheSize];
private struct Entry
{
public int Hash { get; }
public SyntaxToken Token { get; }
internal Entry(int hash, SyntaxToken token)
{
Hash = hash;
Token = token;
}
}
public static SyntaxToken GetToken(string content)
{
var hash = content.GetHashCode();
var idx = hash & CacheMask;
var e = s_cache[idx];
if (e.Hash == hash && e.Token?.Content == content)
{
return e.Token;
}
var token = new SyntaxToken(SyntaxKind.Whitespace, content, Array.Empty<RazorDiagnostic>());
s_cache[idx] = new Entry(hash, token);
return token;
}
}
}