Skip to content

Commit 016fd1e

Browse files
authored
Improve CSharpLanguageCharacteristics.MapKeyword performance (dotnet/razor#1879)
* Improve CSharpLanguageCharacteristics.MapKeyword performance The razor typing perf test profile I'm looking at has 156 ms of CPU cycles spent in this method, mostly in Enum.ToString() \n\nCommit migrated from dotnet/razor@e821a46
1 parent a70de6b commit 016fd1e

File tree

1 file changed

+107
-3
lines changed

1 file changed

+107
-3
lines changed

src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/CSharpLanguageCharacteristics.cs

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Diagnostics;
67
using Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax;
@@ -9,8 +10,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
910
{
1011
internal class CSharpLanguageCharacteristics : LanguageCharacteristics<CSharpTokenizer>
1112
{
12-
private static readonly CSharpLanguageCharacteristics _instance = new CSharpLanguageCharacteristics();
13-
1413
private static Dictionary<SyntaxKind, string> _tokenSamples = new Dictionary<SyntaxKind, string>()
1514
{
1615
{ SyntaxKind.Arrow, "->" },
@@ -64,8 +63,108 @@ internal class CSharpLanguageCharacteristics : LanguageCharacteristics<CSharpTok
6463
{ SyntaxKind.Transition, "@" },
6564
};
6665

66+
// Allows performance optimization of GetKeyword such that it need not do Enum.ToString
67+
private static IReadOnlyDictionary<CSharpKeyword, string> _keywordNames = new Dictionary<CSharpKeyword, string>()
68+
{
69+
{ CSharpKeyword.Await, "await" },
70+
{ CSharpKeyword.Abstract, "abstract" },
71+
{ CSharpKeyword.Byte, "byte" },
72+
{ CSharpKeyword.Class, "class" },
73+
{ CSharpKeyword.Delegate, "delegate" },
74+
{ CSharpKeyword.Event, "event" },
75+
{ CSharpKeyword.Fixed, "fixed" },
76+
{ CSharpKeyword.If, "if" },
77+
{ CSharpKeyword.Internal, "internal" },
78+
{ CSharpKeyword.New, "new" },
79+
{ CSharpKeyword.Override, "override" },
80+
{ CSharpKeyword.Readonly, "readonly" },
81+
{ CSharpKeyword.Short, "short" },
82+
{ CSharpKeyword.Struct, "struct" },
83+
{ CSharpKeyword.Try, "try" },
84+
{ CSharpKeyword.Unsafe, "unsafe" },
85+
{ CSharpKeyword.Volatile, "volatile" },
86+
{ CSharpKeyword.As, "as" },
87+
{ CSharpKeyword.Do, "do" },
88+
{ CSharpKeyword.Is, "is" },
89+
{ CSharpKeyword.Params, "params" },
90+
{ CSharpKeyword.Ref, "ref" },
91+
{ CSharpKeyword.Switch, "switch" },
92+
{ CSharpKeyword.Ushort, "ushort" },
93+
{ CSharpKeyword.While, "while" },
94+
{ CSharpKeyword.Case, "case" },
95+
{ CSharpKeyword.Const, "const" },
96+
{ CSharpKeyword.Explicit, "explicit" },
97+
{ CSharpKeyword.Float, "float" },
98+
{ CSharpKeyword.Null, "null" },
99+
{ CSharpKeyword.Sizeof, "sizeof" },
100+
{ CSharpKeyword.Typeof, "typeof" },
101+
{ CSharpKeyword.Implicit, "implicit" },
102+
{ CSharpKeyword.Private, "private" },
103+
{ CSharpKeyword.This, "this" },
104+
{ CSharpKeyword.Using, "using" },
105+
{ CSharpKeyword.Extern, "extern" },
106+
{ CSharpKeyword.Return, "return" },
107+
{ CSharpKeyword.Stackalloc, "stackalloc" },
108+
{ CSharpKeyword.Uint, "uint" },
109+
{ CSharpKeyword.Base, "base" },
110+
{ CSharpKeyword.Catch, "catch" },
111+
{ CSharpKeyword.Continue, "continue" },
112+
{ CSharpKeyword.Double, "double" },
113+
{ CSharpKeyword.For, "for" },
114+
{ CSharpKeyword.In, "in" },
115+
{ CSharpKeyword.Lock, "lock" },
116+
{ CSharpKeyword.Object, "object" },
117+
{ CSharpKeyword.Protected, "protected" },
118+
{ CSharpKeyword.Static, "static" },
119+
{ CSharpKeyword.False, "false" },
120+
{ CSharpKeyword.Public, "public" },
121+
{ CSharpKeyword.Sbyte, "sbyte" },
122+
{ CSharpKeyword.Throw, "throw" },
123+
{ CSharpKeyword.Virtual, "virtual" },
124+
{ CSharpKeyword.Decimal, "decimal" },
125+
{ CSharpKeyword.Else, "else" },
126+
{ CSharpKeyword.Operator, "operator" },
127+
{ CSharpKeyword.String, "string" },
128+
{ CSharpKeyword.Ulong, "ulong" },
129+
{ CSharpKeyword.Bool, "bool" },
130+
{ CSharpKeyword.Char, "char" },
131+
{ CSharpKeyword.Default, "default" },
132+
{ CSharpKeyword.Foreach, "foreach" },
133+
{ CSharpKeyword.Long, "long" },
134+
{ CSharpKeyword.Void, "void" },
135+
{ CSharpKeyword.Enum, "enum" },
136+
{ CSharpKeyword.Finally, "finally" },
137+
{ CSharpKeyword.Int, "int" },
138+
{ CSharpKeyword.Out, "out" },
139+
{ CSharpKeyword.Sealed, "sealed" },
140+
{ CSharpKeyword.True, "true" },
141+
{ CSharpKeyword.Goto, "goto" },
142+
{ CSharpKeyword.Unchecked, "unchecked" },
143+
{ CSharpKeyword.Interface, "interface" },
144+
{ CSharpKeyword.Break, "break" },
145+
{ CSharpKeyword.Checked, "checked" },
146+
{ CSharpKeyword.Namespace, "namespace" },
147+
{ CSharpKeyword.When, "when" },
148+
};
149+
150+
private static readonly CSharpLanguageCharacteristics _instance = new CSharpLanguageCharacteristics();
151+
67152
protected CSharpLanguageCharacteristics()
68153
{
154+
#if DEBUG
155+
var values = Enum.GetValues(typeof(CSharpKeyword));
156+
157+
Debug.Assert(values.Length == _keywordNames.Count, "_keywordNames and CSharpKeyword are out of sync");
158+
for (var i = 0; i < values.Length; i++)
159+
{
160+
var keyword = (CSharpKeyword) values.GetValue(i);
161+
162+
var expectedValue = keyword.ToString().ToLowerInvariant();
163+
var actualValue = _keywordNames[keyword];
164+
165+
Debug.Assert(expectedValue == actualValue, "_keywordNames and CSharpKeyword are out of sync for " + expectedValue);
166+
}
167+
#endif
69168
}
70169

71170
public static CSharpLanguageCharacteristics Instance => _instance;
@@ -170,7 +269,12 @@ public override SyntaxKind FlipBracket(SyntaxKind bracket)
170269

171270
public static string GetKeyword(CSharpKeyword keyword)
172271
{
173-
return keyword.ToString().ToLowerInvariant();
272+
if (!_keywordNames.TryGetValue(keyword, out var value))
273+
{
274+
value = keyword.ToString().ToLowerInvariant();
275+
}
276+
277+
return value;
174278
}
175279
}
176280
}

0 commit comments

Comments
 (0)