diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 63bb6d2d51..9cea453367 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -991,13 +991,13 @@ func makePush(size uint64, pushByteSize int) executionFunc { start = min(codeLen, int(*pc+1)) end = min(codeLen, start+pushByteSize) ) - a := new(uint256.Int).SetBytes(scope.Contract.Code[start:end]) + a := scope.Stack.get() + a.SetBytes(scope.Contract.Code[start:end]) // Missing bytes: pushByteSize - len(pushData) if missing := pushByteSize - (end - start); missing > 0 { a.Lsh(a, uint(8*missing)) } - scope.Stack.push(a) *pc += size return nil, nil } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index cce88eebb5..07557b8c9a 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -24,6 +24,7 @@ import ( "os" "strings" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -281,25 +282,40 @@ func TestJsonTestcases(t *testing.T) { func opBenchmark(bench *testing.B, op executionFunc, args ...string) { var ( - evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) - stack = newStackForTesting() - scope = &ScopeContext{nil, stack, nil} + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newStackForTesting() + code = []byte{} + opPush32 = makePush(32, 32) ) // convert args intArgs := make([]*uint256.Int, len(args)) for i, arg := range args { + code = append(code, common.LeftPadBytes(common.Hex2Bytes(arg), 32)...) intArgs[i] = new(uint256.Int).SetBytes(common.Hex2Bytes(arg)) } pc := uint64(0) + scope := &ScopeContext{nil, stack, &Contract{Code: code}} + start := time.Now() bench.ResetTimer() for i := 0; i < bench.N; i++ { - for _, arg := range intArgs { - stack.push(arg) + for range len(args) { + opPush32(&pc, evm.interpreter, scope) + pc += 32 } op(&pc, evm.interpreter, scope) - stack.pop() + opPop(&pc, evm.interpreter, scope) } bench.StopTimer() + elapsed := uint64(time.Since(start)) + if elapsed < 1 { + elapsed = 1 + } + reqGas := uint64(len(args))*GasFastestStep + GasFastestStep + GasQuickStep + gasUsed := reqGas * uint64(bench.N) + bench.ReportMetric(float64(reqGas), "gas/op") + // Keep it as uint64, multiply 100 to get two digit float later + mgasps := (100 * 1000 * gasUsed) / elapsed + bench.ReportMetric(float64(mgasps)/100, "mgas/s") for i, arg := range args { want := new(uint256.Int).SetBytes(common.Hex2Bytes(arg)) diff --git a/core/vm/stack.go b/core/vm/stack.go index 11b305d20f..36a73b9a87 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -29,28 +29,24 @@ type stackArena struct { } func (sa *stackArena) push(value *uint256.Int) { - if len(sa.data) <= sa.top { - // we need to grow the arena - sa.data = slices.Grow(sa.data, 512) - sa.data = sa.data[:cap(sa.data)] - } - sa.data[sa.top] = *value - sa.top++ -} -func (sa *stackArena) pop() { - sa.top-- } func newArena() *stackArena { return &stackArena{ - data: make([]uint256.Int, 1024), + data: make([]uint256.Int, 1025), } } // stack returns an instance of a stack which uses the underlying arena. The instance // must be released by invoking the (*Stack).release() method func (sa *stackArena) stack() *Stack { + // make sure every substack has at least 1024 elements + if len(sa.data) <= sa.top+1024 { + // we need to grow the arena + sa.data = slices.Grow(sa.data, 1024) + sa.data = sa.data[:cap(sa.data)] + } return &Stack{ bottom: sa.top, size: 0, @@ -62,7 +58,7 @@ func (sa *stackArena) stack() *Stack { // backed by a newly allocated arena. func newStackForTesting() *Stack { arena := &stackArena{ - data: make([]uint256.Int, 256), + data: make([]uint256.Int, 1025), } return arena.stack() } @@ -89,16 +85,22 @@ func (s *Stack) Data() []uint256.Int { } func (s *Stack) push(d *uint256.Int) { - // NOTE push limit (1024) is checked in baseCheck - s.inner.push(d) + s.inner.data[s.inner.top] = *d + s.inner.top++ s.size++ } +func (s *Stack) get() *uint256.Int { + elem := &s.inner.data[s.inner.top] + s.inner.top++ + s.size++ + return elem +} + func (s *Stack) pop() uint256.Int { - ret := s.inner.data[s.bottom+s.size-1] - s.inner.pop() + s.inner.top-- s.size-- - return ret + return s.inner.data[s.inner.top] } func (s *Stack) len() int { @@ -155,7 +157,6 @@ func (s *Stack) swap16() { } func (s *Stack) dup(n int) { - // TODO: check size of inner s.inner.data[s.bottom+s.size] = s.inner.data[s.bottom+s.size-n] s.size++ s.inner.top++