diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/GreenNode.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/GreenNode.cs index 0ee39cc7951..7089508b61b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/GreenNode.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/GreenNode.cs @@ -8,7 +8,9 @@ using System.Globalization; using System.IO; using System.Runtime.CompilerServices; +using System.Text; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.Extensions.ObjectPool; namespace Microsoft.AspNetCore.Razor.Language.Syntax; @@ -22,6 +24,12 @@ internal abstract class GreenNode private static readonly ConditionalWeakTable AnnotationsTable = new ConditionalWeakTable(); + /// + /// Pool of StringWriters for use in . Users should not dispose the StringWriter directly + /// (but should dispose of the PooledObject returned from Pool.GetPooledObject). + /// + private static readonly ObjectPool StringWriterPool = DefaultPool.Create(Policy.Instance); + private int _width; private byte _slotCount; @@ -234,10 +242,11 @@ private string GetDebuggerDisplay() public override string ToString() { - using var _ = StringBuilderPool.GetPooledObject(out var builder); - using var writer = new StringWriter(builder, CultureInfo.InvariantCulture); + using var _ = StringWriterPool.GetPooledObject(out var writer); + WriteTo(writer); - return builder.ToString(); + + return writer.ToString(); } public void WriteTo(TextWriter writer) @@ -351,4 +360,30 @@ public SyntaxNode CreateRed() public abstract TResult Accept(InternalSyntax.SyntaxVisitor visitor); public abstract void Accept(InternalSyntax.SyntaxVisitor visitor); + + private sealed class Policy : IPooledObjectPolicy + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public StringWriter Create() + => new StringWriter(new StringBuilder(), CultureInfo.InvariantCulture); + + public bool Return(StringWriter writer) + { + var builder = writer.GetStringBuilder(); + + // Very similar to StringBuilderPool.Policy implementation. + builder.Clear(); + if (builder.Capacity > DefaultPool.MaximumObjectSize) + { + builder.Capacity = DefaultPool.MaximumObjectSize; + } + + return true; + } + } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxNodeExtensions.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxNodeExtensions.cs index 198cac936c5..c4439108ff2 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxNodeExtensions.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.CSharp; namespace Microsoft.AspNetCore.Razor.Language.Syntax; @@ -303,11 +302,7 @@ public static TRoot InsertNodesAfter(this TRoot root, SyntaxNode nodeInLi public static string GetContent(this TNode node) where TNode : SyntaxNode { - using var _ = StringBuilderPool.GetPooledObject(out var builder); - using var writer = new System.IO.StringWriter(builder); - node.Green.WriteTo(writer); - - return writer.ToString(); + return node.Green.ToString(); } private sealed class DiagnosticSyntaxWalker(List diagnostics) : SyntaxWalker