core/vm: hoist jumptable nil-check out of the interpreter loop

This commit is contained in:
Ömer Faruk IRMAK 2025-06-20 14:41:54 +03:00
parent 09289fd154
commit 301d5a8b27
2 changed files with 25 additions and 5 deletions

View file

@ -182,6 +182,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
var (
op OpCode // current opcode
jumpTable *JumpTable = in.table
mem = NewMemory() // bound memory
stack = newstack() // local stack
callContext = &ScopeContext{
@ -227,6 +228,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
// the execution of one of the operations or until the done flag is set by the
// parent context.
_ = jumpTable[0] // nil-check the jumpTable out of the loop
for {
if debug {
// Capture pre-execution values for tracing.
@ -247,7 +249,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// Get the operation from the jump table and validate the stack to ensure there are
// enough stack items available to perform the operation.
op = contract.GetOp(pc)
operation := in.table[op]
operation := jumpTable[op]
cost = operation.constantGas // For tracing
// Validate stack
if sLen := stack.len(); sLen < operation.minStack {

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"
)
var loopInterruptTests = []string{
@ -74,3 +75,20 @@ func TestLoopInterrupt(t *testing.T) {
}
}
}
func BenchmarkLoop(b *testing.B) {
address := common.BytesToAddress([]byte("contract"))
vmctx := BlockContext{
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
}
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.CreateAccount(address)
statedb.SetCode(address, common.Hex2Bytes(loopInterruptTests[0]))
statedb.Finalise(true)
evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{})
b.ResetTimer()
_, _, err := evm.Call(common.Address{}, address, nil, uint64(b.N*100), new(uint256.Int))
require.EqualError(b, err, ErrOutOfGas.Error())
}