Skip to content

Commit 9e3c616

Browse files
🐛 JSON decode, ensure use of provided ArrayPool<byte>
1 parent b765bd1 commit 9e3c616

File tree

1 file changed

+51
-31
lines changed

1 file changed

+51
-31
lines changed

TronDotNet.SystemTextJson/TronJsonDecoder.cs

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ public static async Task<DecodeResult> DecodeAsync(
111111
ArrayPool<byte>? arrayPool,
112112
CancellationToken cancellationToken)
113113
{
114+
var growBuffer = arrayPool != null;
114115
var isRentedBuffer = false;
116+
117+
arrayPool ??= ArrayPool<byte>.Shared;
118+
115119
if (buffer == null)
116120
{
117121
if (arrayPool == null)
@@ -151,9 +155,10 @@ public static async Task<DecodeResult> DecodeAsync(
151155
var jsonReader = new Utf8JsonReader(readerBuffer, isCompleted, readerState);
152156

153157
var status = DecodeCore(
158+
arrayPool,
154159
ref frames,
155160
ref buffer,
156-
arrayPool,
161+
growBuffer,
157162
ref isRentedBuffer,
158163
ref position,
159164
ref jsonReader);
@@ -199,7 +204,11 @@ private static (byte[] Buffer, int Position) DecodeImpl(
199204
ReadOnlySpan<byte> utf8Json,
200205
ArrayPool<byte>? arrayPool)
201206
{
207+
var growBuffer = arrayPool != null;
202208
var isRentedBuffer = false;
209+
210+
arrayPool ??= ArrayPool<byte>.Shared;
211+
203212
if (buffer == null)
204213
{
205214
if (arrayPool == null)
@@ -215,10 +224,10 @@ private static (byte[] Buffer, int Position) DecodeImpl(
215224

216225
do
217226
{
218-
var status = DecodeCore(
227+
var status = DecodeCore(arrayPool,
219228
ref frames,
220229
ref buffer,
221-
arrayPool,
230+
growBuffer,
222231
ref isRentedBuffer,
223232
ref position,
224233
ref jsonReader);
@@ -234,9 +243,10 @@ private static (byte[] Buffer, int Position) DecodeImpl(
234243
}
235244

236245
private static Lite3.Status DecodeCore(
246+
ArrayPool<byte> arrayPool,
237247
ref FrameStack frames,
238248
ref byte[] buffer,
239-
ArrayPool<byte>? arrayPool,
249+
bool growBuffer,
240250
ref bool isRentedBuffer,
241251
ref int position,
242252
ref Utf8JsonReader reader)
@@ -252,16 +262,16 @@ private static Lite3.Status DecodeCore(
252262

253263
var status = frame.Kind switch
254264
{
255-
FrameKind.Object => DecodeObject(ref frames, replayToken, ref reader),
256-
FrameKind.ObjectSwitch => DecodeObjectSwitch(ref frames, buffer, ref position, replayToken, ref reader),
257-
FrameKind.Array => DecodeArray(ref frames, replayToken, ref reader),
258-
FrameKind.ArraySwitch => DecodeArraySwitch(ref frames, buffer, ref position, ref reader),
265+
FrameKind.Object => DecodeObject(arrayPool, ref frames, replayToken, ref reader),
266+
FrameKind.ObjectSwitch => DecodeObjectSwitch(arrayPool, ref frames, buffer, ref position, replayToken, ref reader),
267+
FrameKind.Array => DecodeArray(arrayPool, ref frames, replayToken, ref reader),
268+
FrameKind.ArraySwitch => DecodeArraySwitch(arrayPool, ref frames, buffer, ref position, ref reader),
259269
_ => throw new InvalidDataException("Unknown frame kind.")
260270
};
261271

262272
replayToken = false;
263273

264-
if (status == Lite3.Status.InsufficientBuffer && arrayPool != null)
274+
if (status == Lite3.Status.InsufficientBuffer && growBuffer)
265275
{
266276
status = TronBuffer.Grow(arrayPool, isRentedBuffer, buffer, out buffer);
267277
isRentedBuffer = true;
@@ -307,6 +317,7 @@ private static Lite3.Status DecodeDocument(
307317
}
308318

309319
private static Lite3.Status DecodeObject(
320+
ArrayPool<byte> arrayPool,
310321
ref FrameStack frames,
311322
bool replayToken,
312323
ref Utf8JsonReader reader)
@@ -323,21 +334,22 @@ private static Lite3.Status DecodeObject(
323334
{
324335
if (reader.TokenType == JsonTokenType.EndObject)
325336
{
326-
frames.Pop();
337+
frames.Pop(arrayPool);
327338
return 0;
328339
}
329340

330341
if (reader.TokenType != JsonTokenType.PropertyName)
331342
return Lite3.Status.ExpectedJsonProperty;
332343

333-
frames.Push(Frame.ForObjectSwitch(offset, GetKeyRef(ref reader)));
344+
frames.Push(Frame.ForObjectSwitch(offset, GetKeyRef(arrayPool, ref reader)));
334345
return 0;
335346
}
336347

337348
return reader.IsFinalBlock ? Lite3.Status.InsufficientBuffer : Lite3.Status.NeedsMoreData;
338349
}
339350

340351
private static Lite3.Status DecodeObjectSwitch(
352+
ArrayPool<byte> arrayPool,
341353
ref FrameStack frames,
342354
byte[] buffer,
343355
ref int position,
@@ -377,17 +389,17 @@ private static Lite3.Status DecodeObjectSwitch(
377389
}
378390
case JsonTokenType.String:
379391
{
380-
var value = ReadUtf8Value(ref reader, out var rentedBuffer);
392+
var value = ReadUtf8Value(arrayPool, ref reader, out var rentedBuffer);
381393
status = Lite3.SetString(buffer, ref position, offset, key, keyData, value);
382394
if (rentedBuffer != null)
383-
ArrayPool<byte>.Shared.Return(rentedBuffer);
395+
arrayPool.Return(rentedBuffer);
384396
break;
385397
}
386398
case JsonTokenType.StartObject:
387399
{
388400
if ((status = Lite3.SetObject(buffer, ref position, offset, key, keyData, out var objectOffset)) >= 0)
389401
{
390-
frames.Pop();
402+
frames.Pop(arrayPool);
391403
frames.Push(Frame.ForObject(objectOffset));
392404
}
393405

@@ -397,7 +409,7 @@ private static Lite3.Status DecodeObjectSwitch(
397409
{
398410
if ((status = Lite3.SetArray(buffer, ref position, offset, key, keyData, out var arrayOffset)) >= 0)
399411
{
400-
frames.Pop();
412+
frames.Pop(arrayPool);
401413
frames.Push(Frame.ForArray(arrayOffset));
402414
}
403415

@@ -411,12 +423,16 @@ private static Lite3.Status DecodeObjectSwitch(
411423
if (status < 0)
412424
return status;
413425

414-
frames.Pop();
426+
frames.Pop(arrayPool);
415427

416428
return status;
417429
}
418430

419-
private static Lite3.Status DecodeArray(ref FrameStack frames, bool replayToken, ref Utf8JsonReader reader)
431+
private static Lite3.Status DecodeArray(
432+
ArrayPool<byte> arrayPool,
433+
ref FrameStack frames,
434+
bool replayToken,
435+
ref Utf8JsonReader reader)
420436
{
421437
if (reader.CurrentDepth > JsonConstants.NestingDepthMax)
422438
return Lite3.Status.JsonNestingDepthExceededMax;
@@ -430,7 +446,7 @@ private static Lite3.Status DecodeArray(ref FrameStack frames, bool replayToken,
430446
{
431447
if (reader.TokenType == JsonTokenType.EndArray)
432448
{
433-
frames.Pop();
449+
frames.Pop(arrayPool);
434450
return 0;
435451
}
436452

@@ -442,6 +458,7 @@ private static Lite3.Status DecodeArray(ref FrameStack frames, bool replayToken,
442458
}
443459

444460
private static Lite3.Status DecodeArraySwitch(
461+
ArrayPool<byte> arrayPool,
445462
ref FrameStack frames,
446463
byte[] buffer,
447464
ref int position,
@@ -474,17 +491,17 @@ private static Lite3.Status DecodeArraySwitch(
474491
}
475492
case JsonTokenType.String:
476493
{
477-
var value = ReadUtf8Value(ref reader, out var rentedBuffer);
494+
var value = ReadUtf8Value(arrayPool, ref reader, out var rentedBuffer);
478495
status = Lite3.ArrayAppendString(buffer, ref position, offset, value);
479496
if (rentedBuffer != null)
480-
ArrayPool<byte>.Shared.Return(rentedBuffer);
497+
arrayPool.Return(rentedBuffer);
481498
break;
482499
}
483500
case JsonTokenType.StartObject:
484501
{
485502
if ((status = Lite3.ArrayAppendObject(buffer, ref position, offset, out var objectOffset)) >= 0)
486503
{
487-
frames.Pop();
504+
frames.Pop(arrayPool);
488505
frames.Push(Frame.ForObject(objectOffset));
489506
}
490507

@@ -494,7 +511,7 @@ private static Lite3.Status DecodeArraySwitch(
494511
{
495512
if ((status = Lite3.ArrayAppendArray(buffer, ref position, offset, out var arrayOffset)) >= 0)
496513
{
497-
frames.Pop();
514+
frames.Pop(arrayPool);
498515
frames.Push(Frame.ForArray(arrayOffset));
499516
}
500517

@@ -505,12 +522,12 @@ private static Lite3.Status DecodeArraySwitch(
505522
break;
506523
}
507524

508-
frames.Pop();
525+
frames.Pop(arrayPool);
509526

510527
return status;
511528
}
512529

513-
private static KeyRef GetKeyRef(ref Utf8JsonReader reader)
530+
private static KeyRef GetKeyRef(ArrayPool<byte> arrayPool, ref Utf8JsonReader reader)
514531
{
515532
var length = reader.HasValueSequence
516533
? checked((int)reader.ValueSequence.Length)
@@ -530,7 +547,7 @@ private static KeyRef GetKeyRef(ref Utf8JsonReader reader)
530547
};
531548
}
532549

533-
var pooledKey = ArrayPool<byte>.Shared.Rent(length);
550+
var pooledKey = arrayPool.Rent(length);
534551

535552
length = reader.CopyString(pooledKey);
536553

@@ -543,15 +560,18 @@ private static KeyRef GetKeyRef(ref Utf8JsonReader reader)
543560
}
544561

545562
[MethodImpl(MethodImplOptions.AggressiveInlining)]
546-
private static ReadOnlySpan<byte> ReadUtf8Value(ref Utf8JsonReader reader, out byte[]? rented)
563+
private static ReadOnlySpan<byte> ReadUtf8Value(
564+
ArrayPool<byte> arrayPool,
565+
ref Utf8JsonReader reader,
566+
out byte[]? rented)
547567
{
548568
if (reader.HasValueSequence || reader.ValueIsEscaped)
549569
{
550570
var length = reader.HasValueSequence
551571
? checked((int)reader.ValueSequence.Length)
552572
: reader.ValueSpan.Length;
553573

554-
rented = ArrayPool<byte>.Shared.Rent(length);
574+
rented = arrayPool.Rent(length);
555575
length = reader.CopyString(rented);
556576

557577
return rented.AsSpan(0, length);
@@ -582,12 +602,12 @@ public Lite3.Status Push(in Frame frame)
582602
}
583603

584604
[MethodImpl(MethodImplOptions.AggressiveInlining)]
585-
public void Pop()
605+
public void Pop(ArrayPool<byte> arrayPool)
586606
{
587607
ref var frame = ref _frames[_index];
588608

589609
if (frame is { Kind: FrameKind.ObjectSwitch })
590-
frame.KeyRef.Return();
610+
frame.KeyRef.Return(arrayPool);
591611

592612
_frames[_index--] = default;
593613
}
@@ -643,10 +663,10 @@ private struct KeyRef
643663
};
644664

645665
[MethodImpl(MethodImplOptions.AggressiveInlining)]
646-
public void Return()
666+
public void Return(ArrayPool<byte> arrayPool)
647667
{
648668
if (Kind == KeyRefKind.Pooled && PooledKey != null)
649-
ArrayPool<byte>.Shared.Return(PooledKey);
669+
arrayPool.Return(PooledKey);
650670
}
651671
}
652672

0 commit comments

Comments
 (0)