Repository navigation
Port upstream EVM memory resize perf fix (PLT-1111) #100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,6 +48,7 @@ func (m *Memory) Free() { | |
| // To reduce peak allocation, return only smaller memory instances to the pool. | ||
| const maxBufferSize = 16 << 10 | ||
| if cap(m.store) <= maxBufferSize { | ||
| clear(m.store) | ||
| m.store = m.store[:0] | ||
| m.lastGasCost = 0 | ||
| memoryPool.Put(m) | ||
|
|
@@ -80,10 +81,14 @@ func (m *Memory) Set32(offset uint64, val *uint256.Int) { | |
| val.PutUint256(m.store[offset:]) | ||
| } | ||
|
|
||
| // Resize resizes the memory to size | ||
| // Resize grows the memory to the requested size. | ||
| func (m *Memory) Resize(size uint64) { | ||
| if uint64(m.Len()) < size { | ||
| m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) | ||
| if uint64(len(m.store)) < size { | ||
| if uint64(cap(m.store)) >= size { | ||
| m.store = m.store[:size] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [suggestion] This fast path is only sound because |
||
| } else { | ||
| m.store = append(m.store, make([]byte, size-uint64(len(m.store)))...) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,3 +83,10 @@ func TestMemoryCopy(t *testing.T) { | |
| } | ||
| } | ||
| } | ||
|
|
||
| func BenchmarkResize(b *testing.B) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [suggestion] The PR body correctly identifies the Consider adding a test that exercises the pool reuse cycle directly: |
||
| memory := NewMemory() | ||
| for i := range b.N { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] This benchmark never frees or resets, so Upstream's version has the same shape, so this is fine to keep as-is for port fidelity. If you'd rather bound it, cycling the size (e.g. |
||
| memory.Resize(uint64(i)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [suggestion] |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[suggestion] This fast path is correct, but it makes an implicit invariant load-bearing for consensus: bytes in
[len(m.store), cap(m.store))must always be zero. I traced it and it currently holds —Freeclears[0, len), theappendbranch below only runs whencap < size(sogrowslicealways reallocates, and Go zeroes[newlen, cap)for pointer-free element types), andSet/Set32/MSTORE8never write pastlen.The risk is that nothing in the code says so. A future change that shrinks
lenwithout clearing — e.g. aReset()doingm.store = m.store[:0], or a truncating resize — would silently expose stale bytes to the EVM and diverge nodes, with no compiler or test to catch it. Worth a short comment here (and at theclear()inFree) stating the invariant and why clearing onlylenbytes is sufficient.