Skip to content

Commit fc88cea

Browse files
authored
core/vm: reuse Memory instances (#30137)
This PR adds a sync.Pool to reuse instances of Memory in EVMInterpreter.
1 parent 3b48b16 commit fc88cea

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

core/vm/instructions.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -871,14 +871,14 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
871871

872872
func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
873873
offset, size := scope.Stack.pop(), scope.Stack.pop()
874-
ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
874+
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
875875

876876
return ret, errStopToken
877877
}
878878

879879
func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
880880
offset, size := scope.Stack.pop(), scope.Stack.pop()
881-
ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
881+
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
882882

883883
interpreter.returnData = ret
884884
return ret, ErrExecutionReverted

core/vm/interpreter.go

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
198198
// they are returned to the pools
199199
defer func() {
200200
returnStack(stack)
201+
mem.Free()
201202
}()
202203
contract.Input = input
203204

core/vm/memory.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@
1717
package vm
1818

1919
import (
20+
"sync"
21+
2022
"github.com/holiman/uint256"
2123
)
2224

25+
var memoryPool = sync.Pool{
26+
New: func() any {
27+
return &Memory{}
28+
},
29+
}
30+
2331
// Memory implements a simple memory model for the ethereum virtual machine.
2432
type Memory struct {
2533
store []byte
@@ -28,7 +36,18 @@ type Memory struct {
2836

2937
// NewMemory returns a new memory model.
3038
func NewMemory() *Memory {
31-
return &Memory{}
39+
return memoryPool.Get().(*Memory)
40+
}
41+
42+
// Free returns the memory to the pool.
43+
func (m *Memory) Free() {
44+
// To reduce peak allocation, return only smaller memory instances to the pool.
45+
const maxBufferSize = 16 << 10
46+
if cap(m.store) <= maxBufferSize {
47+
m.store = m.store[:0]
48+
m.lastGasCost = 0
49+
memoryPool.Put(m)
50+
}
3251
}
3352

3453
// Set sets offset + size to value

core/vm/runtime/runtime_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package runtime
1818

1919
import (
20+
"encoding/binary"
2021
"fmt"
2122
"math/big"
2223
"os"
24+
"strconv"
2325
"strings"
2426
"testing"
2527

@@ -241,6 +243,41 @@ func BenchmarkEVM_SWAP1(b *testing.B) {
241243
})
242244
}
243245

246+
func BenchmarkEVM_RETURN(b *testing.B) {
247+
// returns a contract that returns a zero-byte slice of len size
248+
returnContract := func(size uint64) []byte {
249+
contract := []byte{
250+
byte(vm.PUSH8), 0, 0, 0, 0, 0, 0, 0, 0, // PUSH8 0xXXXXXXXXXXXXXXXX
251+
byte(vm.PUSH0), // PUSH0
252+
byte(vm.RETURN), // RETURN
253+
}
254+
binary.BigEndian.PutUint64(contract[1:], size)
255+
return contract
256+
}
257+
258+
state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
259+
contractAddr := common.BytesToAddress([]byte("contract"))
260+
261+
for _, n := range []uint64{1_000, 10_000, 100_000, 1_000_000} {
262+
b.Run(strconv.FormatUint(n, 10), func(b *testing.B) {
263+
b.ReportAllocs()
264+
265+
contractCode := returnContract(n)
266+
state.SetCode(contractAddr, contractCode)
267+
268+
for i := 0; i < b.N; i++ {
269+
ret, _, err := Call(contractAddr, []byte{}, &Config{State: state})
270+
if err != nil {
271+
b.Fatal(err)
272+
}
273+
if uint64(len(ret)) != n {
274+
b.Fatalf("expected return size %d, got %d", n, len(ret))
275+
}
276+
}
277+
})
278+
}
279+
}
280+
244281
func fakeHeader(n uint64, parentHash common.Hash) *types.Header {
245282
header := types.Header{
246283
Coinbase: common.HexToAddress("0x00000000000000000000000000000000deadbeef"),

0 commit comments

Comments
 (0)