55// #define COLLECT_STATS
66
77using System ;
8- using Microsoft . CodeAnalysis . CSharp . Symbols ;
9- using Microsoft . CodeAnalysis . CSharp . Syntax ;
108using Microsoft . CodeAnalysis . PooledObjects ;
11- using Microsoft . CodeAnalysis . Text ;
9+ using Microsoft . CodeAnalysis . Syntax . InternalSyntax ;
1210using Roslyn . Utilities ;
13- using System . Text ;
1411
1512namespace Microsoft . CodeAnalysis . CSharp . Syntax . InternalSyntax
1613{
17- internal partial class LexerCache
14+ internal class LexerCache
1815 {
16+ private static readonly ObjectPool < LexerCache > s_lexerCachePool = new ObjectPool < LexerCache > ( ( ) => new LexerCache ( ) ) ;
17+
1918 private static readonly ObjectPool < CachingIdentityFactory < string , SyntaxKind > > s_keywordKindPool =
2019 CachingIdentityFactory < string , SyntaxKind > . CreatePool (
2120 512 ,
@@ -30,23 +29,144 @@ internal partial class LexerCache
3029 return kind ;
3130 } ) ;
3231
33- private readonly TextKeyedCache < SyntaxTrivia > _triviaMap ;
34- private readonly TextKeyedCache < SyntaxToken > _tokenMap ;
35- private readonly CachingIdentityFactory < string , SyntaxKind > _keywordKindMap ;
32+ private TextKeyedCache < SyntaxTrivia > ? _triviaMap ;
33+ private TextKeyedCache < SyntaxToken > ? _tokenMap ;
34+ private CachingIdentityFactory < string , SyntaxKind > ? _keywordKindMap ;
3635 internal const int MaxKeywordLength = 10 ;
3736
38- internal LexerCache ( )
37+ private PooledStringBuilder ? _stringBuilder ;
38+ private readonly char [ ] _identBuffer ;
39+ private SyntaxListBuilder ? _leadingTriviaCache ;
40+ private SyntaxListBuilder ? _trailingTriviaCache ;
41+
42+ private const int LeadingTriviaCacheInitialCapacity = 128 ;
43+ private const int TrailingTriviaCacheInitialCapacity = 16 ;
44+
45+ private LexerCache ( )
46+ {
47+ _identBuffer = new char [ 32 ] ;
48+ }
49+
50+ public static LexerCache GetInstance ( )
3951 {
40- _triviaMap = TextKeyedCache < SyntaxTrivia > . GetInstance ( ) ;
41- _tokenMap = TextKeyedCache < SyntaxToken > . GetInstance ( ) ;
42- _keywordKindMap = s_keywordKindPool . Allocate ( ) ;
52+ return s_lexerCachePool . Allocate ( ) ;
4353 }
4454
45- internal void Free ( )
55+ public void Free ( )
4656 {
47- _keywordKindMap . Free ( ) ;
48- _triviaMap . Free ( ) ;
49- _tokenMap . Free ( ) ;
57+ if ( _keywordKindMap != null )
58+ {
59+ _keywordKindMap . Free ( ) ;
60+ _keywordKindMap = null ;
61+ }
62+
63+ if ( _triviaMap != null )
64+ {
65+ _triviaMap . Free ( ) ;
66+ _triviaMap = null ;
67+ }
68+
69+ if ( _tokenMap != null )
70+ {
71+ _tokenMap . Free ( ) ;
72+ _tokenMap = null ;
73+ }
74+
75+ if ( _stringBuilder != null )
76+ {
77+ _stringBuilder . Free ( ) ;
78+ _stringBuilder = null ;
79+ }
80+
81+ if ( _leadingTriviaCache != null )
82+ {
83+ if ( _leadingTriviaCache . Capacity > LeadingTriviaCacheInitialCapacity * 2 )
84+ {
85+ // Don't reuse _leadingTriviaCache if it has grown too large for pooling.
86+ _leadingTriviaCache = null ;
87+ }
88+ else
89+ {
90+ _leadingTriviaCache . Clear ( ) ;
91+ }
92+ }
93+
94+ if ( _trailingTriviaCache != null )
95+ {
96+ if ( _trailingTriviaCache . Capacity > TrailingTriviaCacheInitialCapacity * 2 )
97+ {
98+ // Don't reuse _trailingTriviaCache if it has grown too large for pooling.
99+ _trailingTriviaCache = null ;
100+ }
101+ else
102+ {
103+ _trailingTriviaCache . Clear ( ) ;
104+ }
105+ }
106+
107+ s_lexerCachePool . Free ( this ) ;
108+ }
109+
110+ internal char [ ] IdentBuffer => _identBuffer ;
111+
112+ private TextKeyedCache < SyntaxTrivia > TriviaMap
113+ {
114+ get
115+ {
116+ _triviaMap ??= TextKeyedCache < SyntaxTrivia > . GetInstance ( ) ;
117+
118+ return _triviaMap ;
119+ }
120+ }
121+
122+ private TextKeyedCache < SyntaxToken > TokenMap
123+ {
124+ get
125+ {
126+ _tokenMap ??= TextKeyedCache < SyntaxToken > . GetInstance ( ) ;
127+
128+ return _tokenMap ;
129+ }
130+ }
131+
132+ private CachingIdentityFactory < string , SyntaxKind > KeywordKindMap
133+ {
134+ get
135+ {
136+ _keywordKindMap ??= s_keywordKindPool . Allocate ( ) ;
137+
138+ return _keywordKindMap ;
139+ }
140+ }
141+
142+ internal PooledStringBuilder StringBuilder
143+ {
144+ get
145+ {
146+ _stringBuilder ??= PooledStringBuilder . GetInstance ( ) ;
147+
148+ return _stringBuilder ;
149+ }
150+ }
151+
152+ internal SyntaxListBuilder LeadingTriviaCache
153+ {
154+ get
155+ {
156+ _leadingTriviaCache ??= new SyntaxListBuilder ( LeadingTriviaCacheInitialCapacity ) ;
157+
158+ return _leadingTriviaCache ;
159+ }
160+ }
161+
162+ internal SyntaxListBuilder TrailingTriviaCache
163+ {
164+ get
165+ {
166+ _trailingTriviaCache ??= new SyntaxListBuilder ( TrailingTriviaCacheInitialCapacity ) ;
167+
168+ return _trailingTriviaCache ;
169+ }
50170 }
51171
52172 internal bool TryGetKeywordKind ( string key , out SyntaxKind kind )
@@ -57,7 +177,7 @@ internal bool TryGetKeywordKind(string key, out SyntaxKind kind)
57177 return false ;
58178 }
59179
60- kind = _keywordKindMap . GetOrMakeValue ( key ) ;
180+ kind = KeywordKindMap . GetOrMakeValue ( key ) ;
61181 return kind != SyntaxKind . None ;
62182 }
63183
@@ -69,12 +189,12 @@ internal SyntaxTrivia LookupTrivia<TArg>(
69189 Func < TArg , SyntaxTrivia > createTriviaFunction ,
70190 TArg data )
71191 {
72- var value = _triviaMap . FindItem ( textBuffer , keyStart , keyLength , hashCode ) ;
192+ var value = TriviaMap . FindItem ( textBuffer , keyStart , keyLength , hashCode ) ;
73193
74194 if ( value == null )
75195 {
76196 value = createTriviaFunction ( data ) ;
77- _triviaMap . AddItem ( textBuffer , keyStart , keyLength , hashCode , value ) ;
197+ TriviaMap . AddItem ( textBuffer , keyStart , keyLength , hashCode , value ) ;
78198 }
79199
80200 return value ;
@@ -109,15 +229,15 @@ internal SyntaxToken LookupToken<TArg>(
109229 Func < TArg , SyntaxToken > createTokenFunction ,
110230 TArg data )
111231 {
112- var value = _tokenMap . FindItem ( textBuffer , keyStart , keyLength , hashCode ) ;
232+ var value = TokenMap . FindItem ( textBuffer , keyStart , keyLength , hashCode ) ;
113233
114234 if ( value == null )
115235 {
116236#if COLLECT_STATS
117237 Miss ( ) ;
118238#endif
119239 value = createTokenFunction ( data ) ;
120- _tokenMap . AddItem ( textBuffer , keyStart , keyLength , hashCode , value ) ;
240+ TokenMap . AddItem ( textBuffer , keyStart , keyLength , hashCode , value ) ;
121241 }
122242 else
123243 {
0 commit comments