Skip to content

Commit 300f2f6

Browse files
committed
Improve object pool safety
1 parent d193100 commit 300f2f6

13 files changed

Lines changed: 42 additions & 145 deletions

source/Handlebars/Arguments.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ public void Dispose()
322322
private struct Policy : IInternalObjectPoolPolicy<Enumerator>
323323
{
324324
public Enumerator Create() => new Enumerator();
325-
325+
public bool TryClaim(Enumerator item) => true;
326326
public bool Return(Enumerator item)
327327
{
328328
item.Reset();

source/Handlebars/BindingContext.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ public sealed partial class BindingContext : IDisposable, IHelpersRegistry
1717

1818
internal readonly DeferredValue<BindingContext, ObjectDescriptor> Descriptor;
1919

20-
private BindingContext()
20+
private BindingContext(bool claim)
2121
{
22+
_claimed = claim ? 1 : 0;
23+
2224
InlinePartialTemplates = new CascadeIndex<string, Action<EncodedTextWriter, BindingContext>, StringEqualityComparer>(new StringEqualityComparer(StringComparison.OrdinalIgnoreCase));
2325
Helpers = new CascadeIndex<string, IHelperDescriptor<HelperOptions>, StringEqualityComparer>(new StringEqualityComparer());
2426
BlockHelpers = new CascadeIndex<string, IHelperDescriptor<BlockHelperOptions>, StringEqualityComparer>(new StringEqualityComparer());

source/Handlebars/Collections/ImmutableStack.cs

Lines changed: 0 additions & 84 deletions
This file was deleted.

source/Handlebars/IO/EncodedTextWriterWrapper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public override void Write(object value)
6666
private readonly struct Policy : IInternalObjectPoolPolicy<EncodedTextWriterWrapper>
6767
{
6868
public EncodedTextWriterWrapper Create() => new EncodedTextWriterWrapper();
69+
public bool TryClaim(EncodedTextWriterWrapper item) => true;
6970

7071
public bool Return(EncodedTextWriterWrapper obj)
7172
{

source/Handlebars/IO/PolledStringWriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public Policy(int initialCapacity, int maximumRetainedCapacity = 4096)
4040
}
4141

4242
public ReusableStringWriter Create() => new ReusableStringWriter();
43-
43+
public bool TryClaim(ReusableStringWriter item) => true;
4444
public bool Return(ReusableStringWriter item) => _policy.Return(item.GetStringBuilder());
4545
}
4646
}

source/Handlebars/IO/TextEncoderWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void Dispose()
6666
private struct Policy : IInternalObjectPoolPolicy<TextEncoderWrapper>
6767
{
6868
public TextEncoderWrapper Create() => new TextEncoderWrapper();
69-
69+
public bool TryClaim(TextEncoderWrapper item) => true;
7070
public bool Return(TextEncoderWrapper item)
7171
{
7272
item._enabled = true;

source/Handlebars/Polyfills/AsyncLocal.cs

Lines changed: 0 additions & 35 deletions
This file was deleted.

source/Handlebars/Pools/BindingContext.Pool.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Threading;
12
using HandlebarsDotNet.Compiler;
23
using HandlebarsDotNet.Pools;
34

@@ -17,6 +18,8 @@ internal static BindingContext Create(ICompiledHandlebarsConfiguration configura
1718
{
1819
return Pool.CreateContext(configuration, value, parent, partialBlockTemplate);
1920
}
21+
22+
private int _claimed;
2023

2124
public void Dispose() => Pool.Return(this);
2225

@@ -39,12 +42,23 @@ public BindingContext CreateContext(ICompiledHandlebarsConfiguration configurati
3942
return context;
4043
}
4144

42-
internal struct BindingContextPolicy : IInternalObjectPoolPolicy<BindingContext>
45+
internal readonly struct BindingContextPolicy : IInternalObjectPoolPolicy<BindingContext>
4346
{
44-
public BindingContext Create() => new BindingContext();
47+
public BindingContext Create() => new(claim: true);
48+
49+
public bool TryClaim(BindingContext item)
50+
{
51+
return Interlocked
52+
.CompareExchange(ref item._claimed, 1, 0) == 0;
53+
}
4554

4655
public bool Return(BindingContext item)
4756
{
57+
var shouldReturn = Interlocked
58+
.CompareExchange(ref item._claimed, 0, 1) == 1;
59+
60+
if (!shouldReturn) return false;
61+
4862
item.Root = null;
4963
item.Value = null;
5064
item.ParentContext = null;

source/Handlebars/Pools/ClosureBuilder.Pool.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public ClosureBuilderPool(Policy policy) : base(policy)
3636
private readonly struct Policy : IInternalObjectPoolPolicy<ClosureBuilder>
3737
{
3838
public ClosureBuilder Create() => new ();
39+
public bool TryClaim(ClosureBuilder item) => true;
3940
public bool Return(ClosureBuilder item) => true;
4041
}
4142
}

source/Handlebars/Pools/GenericObjectPool.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ private GenericObjectPool() : base(new Policy()) { }
1010
public readonly struct Policy : IInternalObjectPoolPolicy<T>
1111
{
1212
public T Create() => new ();
13+
public bool TryClaim(T item) => true;
1314
public bool Return(T item) => true;
1415
}
1516
}

0 commit comments

Comments
 (0)