Skip to content

Commit e48227c

Browse files
Pools ClassifiedSpanVisitor instances to reduce allocations
Replaces the pooled `ImmutableArray.Builder` with a pooled `ClassifiedSpanVisitor` to avoid allocating a new visitor instance each time. The `ImmutableArray.Builder` is still effectively pooled, since it is owned by `ClassifiedSpanVisitor`. This change reduces overall memory allocations and improves performance.
1 parent 3d71e4c commit e48227c

File tree

1 file changed

+35
-18
lines changed

1 file changed

+35
-18
lines changed

src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/ClassifiedSpanVisitor.cs

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,40 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy;
1111

1212
internal sealed class ClassifiedSpanVisitor : SyntaxWalker
1313
{
14-
private static readonly ObjectPool<ImmutableArray<ClassifiedSpanInternal>.Builder> Pool = DefaultPool.Create(Policy.Instance, size: 5);
14+
private static readonly ObjectPool<ClassifiedSpanVisitor> Pool = DefaultPool.Create(Policy.Instance, size: 5);
1515

16-
private readonly RazorSourceDocument _source;
1716
private readonly ImmutableArray<ClassifiedSpanInternal>.Builder _spans;
1817

18+
private RazorSourceDocument _source = null!;
1919
private SyntaxNode? _currentBlock;
2020
private SourceSpan? _currentBlockSpan;
2121
private BlockKindInternal _currentBlockKind;
2222

23-
private ClassifiedSpanVisitor(RazorSourceDocument source, ImmutableArray<ClassifiedSpanInternal>.Builder spans)
23+
private ClassifiedSpanVisitor()
2424
{
25-
_source = source;
26-
_spans = spans;
25+
_spans = ImmutableArray.CreateBuilder<ClassifiedSpanInternal>();
26+
_source = null!;
27+
}
2728

29+
private void Initialize(RazorSourceDocument source)
30+
{
31+
_source = source;
2832
_currentBlockKind = BlockKindInternal.Markup;
2933
}
3034

3135
public static ImmutableArray<ClassifiedSpanInternal> VisitRoot(RazorSyntaxTree syntaxTree)
3236
{
33-
using var _ = Pool.GetPooledObject(out var builder);
37+
using var _ = Pool.GetPooledObject(out var visitor);
3438

35-
var visitor = new ClassifiedSpanVisitor(syntaxTree.Source, builder);
39+
visitor.Initialize(syntaxTree.Source);
3640
visitor.Visit(syntaxTree.Root);
3741

38-
return builder.ToImmutableAndClear();
42+
return visitor.GetSpansAndClear();
3943
}
4044

45+
private ImmutableArray<ClassifiedSpanInternal> GetSpansAndClear()
46+
=> _spans.ToImmutableAndClear();
47+
4148
public override void VisitRazorCommentBlock(RazorCommentBlockSyntax node)
4249
{
4350
using (CommentBlock(node))
@@ -426,7 +433,23 @@ private void AddSpan(SyntaxToken token, SpanKindInternal kind, AcceptedCharacter
426433
private void AddSpan(SourceSpan span, SpanKindInternal kind, AcceptedCharactersInternal acceptedCharacters)
427434
=> _spans.Add(new(span, CurrentBlockSpan, kind, _currentBlockKind, acceptedCharacters));
428435

429-
private sealed class Policy : IPooledObjectPolicy<ImmutableArray<ClassifiedSpanInternal>.Builder>
436+
private void Reset()
437+
{
438+
_spans.Clear();
439+
440+
if (_spans.Capacity > Policy.MaximumObjectSize)
441+
{
442+
// Differs from ArrayBuilderPool.Policy's behavior as we allow our array to grow significantly larger
443+
_spans.Capacity = 0;
444+
}
445+
446+
_source = null!;
447+
_currentBlock = null!;
448+
_currentBlockSpan = null;
449+
_currentBlockKind = BlockKindInternal.Markup;
450+
}
451+
452+
private sealed class Policy : IPooledObjectPolicy<ClassifiedSpanVisitor>
430453
{
431454
public static readonly Policy Instance = new();
432455

@@ -438,17 +461,11 @@ private Policy()
438461
{
439462
}
440463

441-
public ImmutableArray<ClassifiedSpanInternal>.Builder Create() => ImmutableArray.CreateBuilder<ClassifiedSpanInternal>();
464+
public ClassifiedSpanVisitor Create() => new();
442465

443-
public bool Return(ImmutableArray<ClassifiedSpanInternal>.Builder builder)
466+
public bool Return(ClassifiedSpanVisitor visitor)
444467
{
445-
builder.Clear();
446-
447-
if (builder.Capacity > MaximumObjectSize)
448-
{
449-
// Differs from ArrayBuilderPool.Policy's behavior as we allow our array to grow significantly larger
450-
builder.Capacity = 0;
451-
}
468+
visitor.Reset();
452469

453470
return true;
454471
}

0 commit comments

Comments
 (0)