From 19eb45376a22f5949e19b9f3f77f73b2f55d8ff7 Mon Sep 17 00:00:00 2001 From: MariusVanDerWijden Date: Wed, 21 May 2025 16:39:58 +0200 Subject: [PATCH] core/vm: reuse stack arena --- core/state_prefetcher.go | 1 + core/state_processor.go | 1 + core/vm/evm.go | 6 ++++++ core/vm/stack.go | 17 ++++++++++++++--- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index f3129f57cd..c94914845c 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -93,6 +93,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c } // Execute the message to preload the implicit touched states evm := vm.NewEVM(NewEVMBlockContext(header, p.chain, nil), stateCpy, p.config, cfg) + defer evm.Free() // Convert the transaction into an executable message and pre-cache its sender msg, err := TransactionToMessage(tx, signer, header.BaseFee) diff --git a/core/state_processor.go b/core/state_processor.go index 322bd24f41..9e504e502b 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -81,6 +81,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } context = NewEVMBlockContext(header, p.chain, nil) evm := vm.NewEVM(context, tracingStateDB, p.config, cfg) + defer evm.Free() if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, evm) diff --git a/core/vm/evm.go b/core/vm/evm.go index c3f11b31b9..46aafc908d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -170,6 +170,12 @@ func (evm *EVM) Cancel() { evm.abort.Store(true) } +// Free returns some memory allocated by the EVM, should be called after the EVM was used +// for the last time. Not necessary, but an improvement. +func (evm *EVM) Free() { + returnStack(evm.arena) +} + // Cancelled returns true if Cancel has been called func (evm *EVM) Cancelled() bool { return evm.abort.Load() diff --git a/core/vm/stack.go b/core/vm/stack.go index d2e93dcdf0..bf885744bb 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -18,6 +18,7 @@ package vm import ( "slices" + "sync" "github.com/holiman/uint256" ) @@ -29,9 +30,19 @@ type stackArena struct { } func newArena() *stackArena { - return &stackArena{ - data: make([]uint256.Int, 1025), - } + return stackPool.New().(*stackArena) +} + +var stackPool = sync.Pool{ + New: func() any { + return &stackArena{ + data: make([]uint256.Int, 1025), + } + }, +} + +func returnStack(arena *stackArena) { + stackPool.Put(arena) } // stack returns an instance of a stack which uses the underlying arena. The instance