Skip to content

Commit eac39a2

Browse files
committed
Merge remote-tracking branch 'origin/master' into evm-stream
# Conflicts: # src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs
2 parents 63741d4 + 3678ca4 commit eac39a2

2 files changed

Lines changed: 46 additions & 10 deletions

File tree

src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ public void CalculateMemoryCost_LengthExceedsULong_ShouldReturnOutOfGas()
7878
Assert.That(result, Is.EqualTo(0L));
7979
}
8080

81+
[TestCase(70 * 1024)]
82+
[TestCase(2 * 1024 * 1024)]
83+
public void Large_pooled_buffer_is_zeroed_on_reuse(int size)
84+
{
85+
EvmPooledMemory dirty = new();
86+
UInt256 zero = UInt256.Zero;
87+
Span<byte> pattern = new byte[size];
88+
pattern.Fill(0xff);
89+
Assert.That(dirty.TrySave(in zero, pattern), Is.True);
90+
dirty.Dispose();
91+
92+
EvmPooledMemory clean = new();
93+
UInt256 length = (UInt256)size;
94+
Assert.That(clean.TryLoadSpan(in zero, in length, out Span<byte> data), Is.True);
95+
Assert.That(data.Length, Is.EqualTo(size));
96+
Assert.That(data.IndexOfAnyExcept((byte)0), Is.EqualTo(-1), "pooled buffer leaked stale data");
97+
clean.Dispose();
98+
}
99+
81100
[Test]
82101
public void CalculateMemoryCost_LengthExceedsLongMax_ShouldReturnOutOfGas()
83102
{

src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,7 @@ private static byte[] RentClean(int minLength)
445445

446446
if (minLength > MaxCachedArrayLength)
447447
{
448-
// Large buffers (Multicall memory, big returndata) would otherwise be fresh LOH allocations
449-
// discarded every frame. Pool them through the runtime's per-core, low-contention shared pool
450-
// rather than a hand-rolled cache: no per-thread large-array retention, no second pool to
451-
// replicate. It may hand back a buffer dirtied by an earlier user, and RentSlow marks the whole
452-
// array as zeroed, so clear the full length first. Buffers above the shared pool's 1 MB ceiling
453-
// fall through to a plain allocation.
454-
byte[] pooled = SafeArrayPool<byte>.Shared.Rent(minLength);
448+
byte[] pooled = RentLarge(minLength);
455449
Array.Clear(pooled);
456450
return pooled;
457451
}
@@ -463,9 +457,7 @@ private static void ReturnClean(byte[] array, int dirtyLength)
463457
{
464458
if (array.Length > MaxCachedArrayLength)
465459
{
466-
// Large buffers only ever come from the shared pool above, so return them there for reuse
467-
// instead of dropping them to GC. Cleared on rent rather than here to avoid double-zeroing.
468-
SafeArrayPool<byte>.Shared.Return(array);
460+
ReturnLarge(array);
469461
return;
470462
}
471463

@@ -477,6 +469,31 @@ private static void ReturnClean(byte[] array, int dirtyLength)
477469
}
478470
}
479471

472+
#if ZK_EVM
473+
private static byte[] RentLarge(int minLength) => SafeArrayPool<byte>.Shared.Rent(minLength);
474+
475+
private static void ReturnLarge(byte[] array) => SafeArrayPool<byte>.Shared.Return(array);
476+
#else
477+
private const int MaxSharedArrayLength = 1 << 20;
478+
// Above this, buffers fall back to plain allocation (not pooled), as before this change.
479+
private const int MaxLargePooledArrayLength = 1 << 22;
480+
private static readonly System.Buffers.ArrayPool<byte> _largeArrayPool =
481+
System.Buffers.ArrayPool<byte>.Create(maxArrayLength: MaxLargePooledArrayLength, maxArraysPerBucket: 16);
482+
483+
private static byte[] RentLarge(int minLength)
484+
=> minLength > MaxSharedArrayLength
485+
? _largeArrayPool.Rent(minLength)
486+
: SafeArrayPool<byte>.Shared.Rent(minLength);
487+
488+
private static void ReturnLarge(byte[] array)
489+
{
490+
if (array.Length > MaxSharedArrayLength)
491+
_largeArrayPool.Return(array);
492+
else
493+
SafeArrayPool<byte>.Shared.Return(array);
494+
}
495+
#endif
496+
480497
[MethodImpl(MethodImplOptions.NoInlining)]
481498
private void RentSlow()
482499
{

0 commit comments

Comments
 (0)